Ruby: ¿amable? vs. instancia_de? vs. is_a?

488

¿Cuál es la diferencia? ¿Cuándo debo usar cuál? ¿Por qué hay tantos de ellos?

Claudiu
fuente
18
En cuanto a por qué tanto is_a?y kind_of?existir: Supongo que es parte de la filosofía de diseño de Ruby. Python diría que solo debería haber una forma de hacer algo; Ruby a menudo tiene métodos sinónimos para que pueda usar el que suena mejor. Es una cuestión de preferencia. Puede deberse en parte a la influencia japonesa: me han dicho que usarán una palabra diferente para el mismo número dependiendo de la oración para que suene mejor. Matz puede haber llevado esa idea al diseño de su lenguaje.
Nathan Long
@NathanLong No creo que los contadores japoneses tengan mucho que ver con eso; todos los idiomas tienen algún tipo de acuerdo y no puedes sustituir un contador por otro la mayor parte del tiempo (por ejemplo, no puedes usar el contador de cilindro para objetos planos; simplemente está mal). Y tiene más que ver con la semántica que con la eufonía.
Casey

Respuestas:

622

kind_of?y is_a?son sinónimos

instance_of?es diferente de los otros dos en que solo regresa truesi el objeto es una instancia de esa clase exacta, no una subclase.

Ejemplo:

  • "hello".is_a? Objecty "hello".kind_of? Objectvolver trueporque "hello"es una Stringy Stringes una subclase de Object.
  • Sin embargo "hello".instance_of? Objectvuelve false.
sepp2k
fuente
77
Simplemente se lee mejor a veces. Piensa @honda.kind_of? Cary @person.is_a? AdministratorRuby tiene que ver con la estética. De hecho, observe el error gramatical ... con el soporte activo puede escribir @person.is_an? Administrator:) ... Eso podría haber llegado al núcleo de Ruby por ahora, en realidad.
rfunduk
2
je, esa es una razón interesante. ¿Puedes romper esto, tú? como puedes anular kind_of?pero no is_a??
Claudiu
3
@thenduks, is_an?no está en ruby-1.9.2-p0. @Claudiu, no. is_a?es solo un alias dekind_of? . Ambos métodos invocar la misma función c, rb_obj_is_kind_of.
ma11hew28
99
@Matt: puede anular un alias sin anular la función con alias. Entonces, sí, puede anular kind_of?sin anular is_a?.
sepp2k
44
¿Dónde está este is_an?método ActiceSupport ? No está en la versión actual de rails, y tampoco puedo encontrar nada en Google sobre que sea obsoleto.
Tom Lord
22

¿Cuál es la diferencia?

De la documentación:

- ( booleano )instance_of?(class)
Devuelve truesi objes una instancia de la clase dada.

y:

- ( Booleano ) is_a?(class)
- ( Booleano )kind_of?(class)
Devuelve truesi classes la clase de obj, o si classes una de las superclases objo módulos incluidos en obj.

Si eso no está claro, sería bueno saber qué es exactamente lo que no está claro, para que la documentación se pueda mejorar.

¿Cuándo debo usar cuál?

Nunca. Utilice el polimorfismo en su lugar.

¿Por qué hay tantos de ellos?

No llamaría a dos "muchos". Hay dos de ellos, porque hacen dos cosas diferentes.

Jörg W Mittag
fuente
3
Creo que mi confusión fue que hay 3, y que 2 simplemente hacen lo mismo y tienen nombres diferentes. Acerca del uso del polimorfismo: estoy de acuerdo, pero la biblioteca estándar de Ruby está llena de usos de cada uno de estos
Claudiu,
44
¿Qué quieres decir con polimorfismo? ¿Es lo mismo que escribir pato?
Andrew Grimm
2
Sí, son lo mismo. La tipificación de patos es una forma de polimorfismo.
SpaceGhost
3
A menudo es mejor hacer polimorfismo, sí, pero hay casos límite en los que realmente desea saber que tiene una clase específica, como cuando se trata de archivos.
Automático
6

Es más parecido a Ruby preguntar a los objetos si responden a un método que necesita o no, utilizando respond_to?. Esto permite una interfaz mínima y una programación inconsciente de implementación.

Por supuesto, no siempre es aplicable, por lo tanto, todavía existe la posibilidad de preguntar sobre una comprensión más conservadora del "tipo", que es clase o una clase base, utilizando los métodos que está solicitando.

Kuonirat
fuente
55
Depende de la situación. Tanto el comentario como el blog pueden responder a created_at. En tal situación es_a? es más apropiado en mi humilde opinión
penkovsky
Eso no tiene sentido, si necesita distinguir un comentario y un objeto de blog entre sí, simplemente no usaría created_at para hacerlo. Eso no impide que pueda escribir un método que tome un objeto que responda a created_at. Si no necesita nada más para hacer su trabajo, puede usarlo con seguridad en Comentarios o Blog, o en cualquier otro modelo de ActiveRecord.
Kingdon
3

Tampoco llamaría a dos muchos ( is_a?y kind_of?son alias del mismo método), pero si desea ver más posibilidades, dirija su atención al #classmétodo:

A = Class.new
B = Class.new A

a, b = A.new, B.new
b.class < A # true - means that b.class is a subclass of A
a.class < B # false - means that a.class is not a subclass of A
# Another possibility: Use #ancestors
b.class.ancestors.include? A # true - means that b.class has A among its ancestors
a.class.ancestors.include? B # false - means that B is not an ancestor of a.class
Boris Stitnicky
fuente
1
Gracias, de hecho estaba preguntando en un sentido general de "qué tipo de información de tiempo de ejecución se puede recopilar en Ruby y cómo", y esto proporciona amplios ejemplos
Claudiu