Ruby: kind_of? contre instance_of? vs is_a?

488

Quelle est la différence? Quand devrais-je utiliser quoi? Pourquoi y en a-t-il autant?

Claudiu
la source
18
Quant à savoir pourquoi is_a?et kind_of?exister: je suppose que cela fait partie de la philosophie de conception de Ruby. Python dirait qu'il ne devrait y avoir qu'une seule façon de faire quelque chose; Ruby a souvent des méthodes synonymes pour que vous puissiez utiliser celle qui sonne le mieux. C'est une question de préférence. Cela peut être en partie dû à l'influence japonaise: on me dit qu'ils utiliseront un mot différent pour le même numéro selon la phrase afin de le rendre plus agréable. Matz a peut-être porté cette idée dans sa conception du langage.
Nathan Long
@NathanLong Je ne pense pas que les compteurs japonais y soient pour beaucoup; toutes les langues ont une sorte d'accord et vous ne pouvez pas remplacer un compteur par un autre la plupart du temps (comme, vous ne pouvez pas utiliser le compteur de cylindre pour les objets plats; c'est juste faux). Et cela a plus à voir avec la sémantique qu'avec l'euphonie.
Casey

Réponses:

622

kind_of?et is_a?sont également synonymes.

instance_of?est différent des deux autres en ce qu'il ne retourne que truesi l'objet est une instance de cette classe exacte, pas une sous-classe.

Exemple:

  • "hello".is_a? Objectet "hello".kind_of? Objectretourner truecar "hello"est un Stringet Stringest une sous-classe de Object.
  • Mais "hello".instance_of? Objectrevient false.
sepp2k
la source
77
Il se lit parfois mieux. Pensez @honda.kind_of? Caret @person.is_a? Administrator, Ruby est tout au sujet de l'esthétique. En fait, remarquez l'erreur grammaticale ... avec un support actif, vous pouvez écrire:) @person.is_an? Administrator... Cela aurait pu en faire maintenant dans le noyau Ruby.
rfunduk
2
heh c'est une raison intéressante. pouvez-vous briser cela, thouugh? comme pouvez-vous remplacer kind_of?mais pas is_a??
Claudiu
3
@thenduks, is_an?n'est pas dans ruby-1.9.2-p0. @Claudiu, non. is_a?est juste un alias dekind_of? . Les deux méthodes Invoke la même fonction c, rb_obj_is_kind_of.
ma11hew28
9
@Matt: vous pouvez remplacer un alias sans remplacer la fonction aliasée. Alors oui, vous pouvez remplacer kind_of?sans remplacer is_a?.
sepp2k
4
Où est cette is_an?méthode ActiceSupport ?! Ce n'est pas dans la version actuelle des rails, et je ne trouve rien sur google à propos de sa dépréciation non plus.
Tom Lord
22

Quelle est la différence?

De la documentation:

- ( booléen )instance_of?(class)
Renvoie trueif objest une instance de la classe donnée.

et:

- ( booléen ) is_a?(class)
- ( booléen )kind_of?(class)
Renvoie trueif classest la classe de obj, ou si classest l'une des superclasses objou des modules inclus dans obj.

Si cela n'est pas clair, il serait bon de savoir exactement ce qui n'est pas clair, afin que la documentation puisse être améliorée.

Quand devrais-je utiliser quoi?

Jamais. Utilisez plutôt le polymorphisme.

Pourquoi y en a-t-il autant?

Je n'appellerais pas deux "beaucoup". Il y en a deux, car ils font deux choses différentes.

Jörg W Mittag
la source
3
Je pense que ma confusion était qu'il y en a 3, et que 2 font juste la même chose et ont des noms différents. À propos de l'utilisation du polymorphisme - Je suis d'accord, mais la bibliothèque standard ruby ​​regorge d'utilisations de chacun d'eux
Claudiu
4
Qu'entendez-vous par polymorphisme? Est-ce la même chose que la saisie de canard?
Andrew Grimm
2
Oui, ce sont les mêmes. Le typage du canard est une forme de polymorphisme.
SpaceGhost
3
Il est souvent préférable de faire du polymorphisme, oui, mais il y a des cas limites où vous voulez vraiment savoir que vous avez une classe spécifique, comme lorsque vous traitez des fichiers.
Automatico
6

Il est plus semblable à Ruby de demander aux objets s'ils répondent à une méthode dont vous avez besoin ou non, en utilisant respond_to?. Cela permet à la fois une programmation minimale sans interface et sans implémentation.

Bien sûr, il n'est pas toujours applicable, il est donc toujours possible de poser des questions sur une compréhension plus conservatrice du "type", qui est une classe ou une classe de base, en utilisant les méthodes que vous demandez.

kuonirat
la source
5
Cela dépend de la situation. Les commentaires et le blog peuvent répondre à created_at. Dans une telle situation is_a? est plus approprié à
mon humble avis
Cela n'a pas de sens, si vous aviez besoin de distinguer un commentaire et un objet de blog l'un de l'autre, vous n'utiliseriez simplement pas created_at pour le faire. Cela n'empêche pas que vous pourriez écrire une méthode qui prend un objet qui répond à created_at. S'il n'a besoin de rien d'autre pour faire son travail, vous pouvez l'utiliser en toute sécurité sur Commentaire ou Blog, ou sur tout autre modèle ActiveRecord.
Kingdon
3

Je n'appellerais pas non plus deux beaucoup ( is_a?et kind_of?sont des alias de la même méthode), mais si vous voulez voir plus de possibilités, portez votre attention sur la #classméthode:

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
la source
1
Merci - je demandais en effet dans un sens général de "quelles informations de type d'exécution peuvent être collectées dans Ruby et comment" - et cela fournit de nombreux exemples
Claudiu