Типы классов Ruby и операторы case

В чем разница между

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

По какой-то причине первый из них иногда работает, а второй - нет, а иногда второй работает, а первый - нет. Почему? Какой из них «правильный» способ сделать это?


person Daisy Sophia Hollman    schedule 11.10.2010    source источник
comment
Строка - это класс. Класс класса - это Class.   -  person Volte    schedule 30.09.2015
comment
Обратите внимание, что MyClass === obj использует Module # = ==, чтобы проверить, является ли obj экземпляром MyClass.   -  person MAGA    schedule 06.05.2020


Ответы (5)


Вы должны использовать:

case item
when MyClass
...

У меня была такая же проблема: Как поймать класс Errno :: ECONNRESET на случай, если когда?

person Nakilon    schedule 11.10.2010
comment
Спасибо! Извините за обман (или своего рода обман), но несколько поисков не нашли ответа на этот предыдущий вопрос. Кажется, что использование === оператором case - довольно распространенная проблема, теперь, когда я вижу, что это проблема. На это, вероятно, следует чаще указывать в учебных пособиях и тому подобном (но я уверен, что многие авторы учебников также не знают об этом). - person Daisy Sophia Hollman; 13.10.2010
comment
Предупреждение, которое не упоминалось при использовании ActiveRecord. Метод ActiveRecord === при сравнении классов использует .is_a ?, что означает, что подклассы класса будут оценивать значение true в операторе case. github.com/rails/blob. - person Jeremy Baker; 08.02.2014

Да, Накилон прав, вы должны знать, как оператор threequal === работает с объектом, указанным в предложении when. В рубине

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

действительно

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

Поймите, что case вызывает метод threequal (например, MyClass.===(item)), и этот метод может быть определен так, чтобы делать все, что вы хотите, а затем вы можете использовать оператор case с точностью.

person Fred    schedule 11.10.2010
comment
Если у меня arr = [], то я заметил, что if Array === arr будет оцениваться как истина, а if arr === Array будет оцениваться как ложь. Может кто-нибудь помочь объяснить? - person Daniel; 21.03.2013
comment
=== - это просто метод, который можно определить, чтобы делать все, что хочет дизайнер класса. Помните также, что a === b на самом деле означает a. === b, поэтому, если вы поменяете местами a и b, вы можете получить другое поведение. Нет гарантии, что === коммутативен. Фактически, Array === Array имеет значение false, но Object === Object истинно, поэтому Array переопределяет семантику ===. - person Fred; 22.03.2013


В 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.

person Ken Bloom    schedule 11.10.2010

Это зависит от характера вашей переменной item. Если это экземпляр объекта, например

t = 5

тогда

t.class == Fixnum

но если это класс сам по себе, например

t = Array

тогда это будет объект Class, поэтому

t.class == Class

ИЗМЕНИТЬ: см. Как поймать Errno :: ECONNRESET класс в случае, когда?, как указано Накилоном, поскольку мой ответ может быть неправильным.

person Jack    schedule 11.10.2010
comment
В Ruby все является экземпляром объекта. - person Eric Duminil; 03.04.2017