Типи класу Ruby та виписки з випадків


135

Яка різниця між

case item.class
when MyClass
  # do something here
when Array
  # do something different here
when String
  # do a third thing
end

і

case item.class
when MyClass.class
  # do something here
when Array.class
  # do something different here
when String.class
  # do a third thing
end

Чомусь перша з них працює іноді, а друга - ні, а інший раз, друга працює, а перша - ні. Чому? Який із них є "правильним" способом це зробити?


1
Рядок - це клас. Клас класу - клас.
Volte

Зауважте, що MyClass === objвикористовується метод Module # ===, щоб перевірити, чи objє примірник MyClass.
Серхіо

Відповіді:


234

Ви повинні використовувати:

case item
when MyClass
...

У мене була така ж проблема: Як зловити Errno :: ECONNRESET клас у "випадку, коли"?


1
Дякую! Вибачте за дуп (або сорт дупа), але кілька запитів не виявили цього попереднього запитання. Здається, використання === у викладі справи є досить поширеною проблемою, тепер, коли я бачу, це проблема. На це, мабуть, слід зазначити частіше в навчальних посібниках і подібних (але, мабуть, я вважаю, що багато письменників-підручників про це теж не знають).
Дейзі Софія Холман

4
Застереження, яке не було згадано при використанні ActiveRecord. Метод ActiveRecord === при порівнянні класів використовує .is_a ?, що означає, що підкласи класу оцінюватимуть як істинне в операторі case. github.com/rails/rails/blob/…
Джеремі Бейкер

61

Так, Накілон правильний, ви повинні знати, як працює оператор threequal === на об'єкт, зазначений у whenпункті. В Рубі

case item
when MyClass
...
when Array
...
when String
...

є насправді

if MyClass === item
...
elsif Array === item
...
elsif String === item
...

Зрозумійте, що виклик викликає метод трирівності ( MyClass.===(item)наприклад), і цей метод можна визначити, щоб робити все, що завгодно, і тоді ви можете використовувати оператор справи з точністю


Якщо я arr = []тоді помітив, що if Array === arrоцінюватиму як істинне, але if arr === Arrayоцінюватиму як хибне. Може хтось допоможе пояснити?
Даніель

4
=== це лише метод, який можна визначити, щоб робити все, що хоче зробити дизайнер класу. Пам'ятайте також, що a === b насправді означає a. === b, тож якщо ви переключите a і b навколо, ви можете отримати іншу поведінку. Немає гарантії, що === є комутативною. Насправді масив === Масив хибний, але Об'єкт === Об'єкт істинний, тому Масив переосмислює семантику ===.
Фред


5

У Ruby ім'я класу - це константа, що посилається на об'єкт типу, Classякий описує певний клас. Це означає, що говорити MyClassв Ruby еквівалентно висловлюванню MyClass.classна Java.

obj.classє об'єктом типу, що Classописує клас obj. Якщо obj.classє MyClass, то objбув створений за допомогою MyClass.new(грубо кажучи). MyClass- це об'єкт типу, Classякий описує будь-який об’єкт, створений за допомогою MyClass.new.

MyClass.class- клас MyClassоб'єкта (це клас об'єкта типу, Classякий описує будь-який об’єкт, створений за допомогою MyClass.new). Іншими словами, MyClass.class == Class.


1

Це залежить від характеру вашої itemзмінної. Якщо це екземпляр об'єкта, наприклад

t = 5

тоді

t.class == Fixnum

але якщо це сам клас, наприклад

t = Array

то це буде Classоб’єкт, так

t.class == Class

EDIT : будь ласка, зверніться до розділу Як зловити Errno :: ECONNRESET клас у "випадку, коли"? як заявив Накілон, оскільки моя відповідь могла бути неправильною.


У Рубі все - "екземпляр об'єкта".
Ерік Думініл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.