Tipos de clase de Ruby y declaraciones de casos

135

Cuál es la diferencia entre

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

y

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

Por alguna razón, el primero de estos funciona a veces y el segundo no, y otras veces, el segundo funciona y el primero no. ¿Por qué? ¿Cuál es la forma "adecuada" de hacerlo?

Daisy Sophia Hollman
fuente
1
La cadena es una clase. La clase de una clase es Clase.
Volte
Tenga en cuenta que MyClass === objutiliza el método Módulo # === para verificar si objes una instancia de MyClass.
sergio

Respuestas:

234

Debes usar:

case item
when MyClass
...

Tuve el mismo problema: ¿Cómo atrapar Errno :: clase ECONNRESET en "caso cuando"?

Nakilon
fuente
1
¡Gracias! Perdón por engañar (o una especie de engaño), pero varias búsquedas no arrojaron esa pregunta anterior. Parece que el uso de === por la declaración del caso es un problema bastante común, ahora que veo que este es el problema. Esto probablemente debería señalarse con más frecuencia en tutoriales y demás (pero apuesto a que muchos escritores de tutoriales tampoco lo saben).
Daisy Sophia Hollman
44
Una advertencia que no se ha mencionado si se usa ActiveRecord. El método ActiveRecord === en las comparaciones de clases utiliza .is_a ?, lo que significa que las subclases de una clase se evaluarán como verdaderas en la declaración del caso. github.com/rails/rails/blob/…
Jeremy Baker
61

Sí, Nakilon es correcto, debe saber cómo funciona el operador threequal === en el objeto dado en la whencláusula. En rubí

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

realmente es

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

Comprenda que case llama a un método threequal ( MyClass.===(item)por ejemplo), y ese método se puede definir para hacer lo que quiera, y luego puede usar la declaración de caso con precisiónw

Fred
fuente
Si lo he hecho arr = [], noté que if Array === arrse evaluará como verdadero pero if arr === Arrayse evaluará como falso. ¿Alguien puede ayudarme a explicar?
Daniel
44
=== es solo un método que se puede definir para hacer lo que el diseñador de una clase quiera que haga. Recuerde, también, que a === b realmente significa a. === b, por lo que si cambia a y b, puede obtener un comportamiento diferente. No hay garantía de que === sea conmutativo. De hecho, Array === Array es falso, pero Object === Object es verdadero, por lo que Array está redefiniendo la semántica de ===.
Fred
13

Puedes usar:

case item.class.to_s
    when 'MyClass'

... cuando el siguiente giro no es posible:

case item
    when MyClass

La razón de esto es que caseusa ===, y la relación ===que describe el operador no es conmutativa . Por ejemplo, 5es un Integer, pero es Integerun 5? Así es como debes pensar en case/ when.

usuario664833
fuente
5

En Ruby, un nombre de clase es una constante que se refiere a un objeto de tipo Classque describe una clase en particular. Eso significa que decir MyClassen Ruby es equivalente a decir MyClass.classen Java.

obj.classes un objeto de tipo que Classdescribe la clase de obj. Si obj.classes así MyClass, objse creó usando MyClass.new(aproximadamente). MyClasses un objeto de tipo Classque describe cualquier objeto creado usando MyClass.new.

MyClass.classes la clase del MyClassobjeto (es la clase del objeto de tipo Classque describe cualquier objeto creado usando MyClass.new). En otras palabras, MyClass.class == Class.

Ken Bloom
fuente
1

Depende de la naturaleza de su itemvariable. Si es una instancia de un objeto, p. Ej.

t = 5

luego

t.class == Fixnum

pero si es una clase en sí misma, por ejemplo

t = Array

entonces será un Classobjeto, entonces

t.class == Class

EDITAR : consulte Cómo capturar la clase Errno :: ECONNRESET en "caso cuando"? como dijo Nakilon ya que mi respuesta podría estar equivocada.

Jack
fuente
En Ruby, todo es "una instancia de un objeto".
Eric Duminil