Ruby: tipo_de? vs. instance_of? vs. is_a?

488

Qual é a diferença? Quando devo usar qual? Por que existem tantos?

Claudiu
fonte
18
Quanto ao porquê de ambos is_a?e kind_of?existir: suponho que seja parte da filosofia de design de Ruby. Python diria que deve haver apenas uma maneira de fazer algo; O Ruby geralmente possui métodos sinônimos, para que você possa usar o que soa melhor. É uma questão de preferência. Pode ser em parte devido à influência japonesa: me disseram que eles usarão uma palavra diferente para o mesmo número, dependendo da frase, a fim de torná-la mais agradável. Matz pode ter levado essa ideia ao seu design de linguagem.
Nathan Long
@ NathanLong Eu não acho que os contadores japoneses tenham muito a ver com isso; todos os idiomas têm algum tipo de acordo e você não pode substituir um contador por outro na maioria das vezes (por exemplo, você não pode usar o contador de cilindros para objetos planos; isso é errado). E tem mais a ver com semântica do que com eufonia.
Casey #

Respostas:

622

kind_of?e is_a?são sinônimos.

instance_of?é diferente dos outros dois, pois só retorna truese o objeto for uma instância dessa classe exata, não uma subclasse.

Exemplo:

  • "hello".is_a? Objecte "hello".kind_of? Objectretornar trueporque "hello"é um StringeString é uma subclasse de Object.
  • No entanto "hello".instance_of? Objectretorna false.
sepp2k
fonte
77
Apenas lê melhor às vezes. Pense @honda.kind_of? Care @person.is_a? Administrator, Ruby, tudo sobre estética. Na verdade, observe o erro gramatical ... com suporte ativo, você pode escrever @person.is_an? Administrator:) ... Isso pode ter chegado ao núcleo do Ruby agora.
Rfunduk 8/10/10
2
heh, essa é uma razão interessante. você pode quebrar isso, rapaz? como você pode substituir, kind_of?mas não is_a??
Claudiu
3
@thenduks, is_an?não está no ruby-1.9.2-p0. @ Claudiu, não. is_a?é apenas um apelido dekind_of? . Ambos os métodos invocam a mesma função c rb_obj_is_kind_of,.
71111 ma11hew28
9
@ Mat: Você pode substituir um alias sem substituir a função de alias. Então, sim, você pode substituir kind_of?sem substituir is_a?.
sepp2k
4
Onde está esse is_an?método ActiceSupport ?! Não está na versão atual dos trilhos, e também não consigo encontrar nada no google sobre isso.
Tom Lord
22

Qual é a diferença?

A partir da documentação:

- ( Booleano )instance_of?(class)
Retorna truese objé uma instância da classe especificada.

e:

- ( Booleano ) is_a?(class)
- ( Booleano )kind_of?(class)
Retorna trueif classé a classe de obj, ou se classé uma das superclasses de objou módulos incluídos em obj.

Se isso não estiver claro, seria bom saber exatamente o que não está claro, para que a documentação possa ser aprimorada.

Quando devo usar qual?

Nunca. Use polimorfismo em seu lugar.

Por que existem tantos?

Eu não chamaria dois "muitos". Existem dois deles, porque eles fazem duas coisas diferentes.

Jörg W Mittag
fonte
3
Eu acho que minha confusão foi que existem 3 e que 2 fazem a mesma coisa e têm nomes diferentes. Sobre o uso de polimorfismo - Concordo, mas a biblioteca padrão do Ruby está cheia de usos de cada um deles
Claudiu
4
O que você quer dizer com polimorfismo? É o mesmo que digitar patos?
Andrew Grimm
2
Sim, são iguais. A digitação de pato é uma forma de polimorfismo.
SpaceGhost 15/01
3
Geralmente é melhor fazer polimorfismo, sim, mas há casos de fronteira em que você realmente deseja saber que possui uma classe específica, como quando está lidando com arquivos.
Automatico
6

É mais parecido com Ruby perguntar aos objetos se eles respondem a um método que você precisa ou não, usando respond_to? . Isso permite que a interface e a implementação mínima sejam inconscientes.

Nem sempre é aplicável, é claro, portanto, ainda existe a possibilidade de perguntar sobre um entendimento mais conservador do "tipo", que é classe ou classe base, usando os métodos que você está perguntando.

kuonirat
fonte
5
Depende da situação. Comentários e Blog podem responder a created_at. Em tal situação é_a? é mais apropriado IMHO
penkovsky 17/05
Isso não faz sentido, se você precisasse distinguir um comentário e um objeto de blog, simplesmente não usaria o created_at para fazer isso. Isso não impede que você possa escrever um método que aceite um objeto que responda a created_at. Se não precisar de mais nada para fazer seu trabalho, você poderá usá-lo com segurança no Comment ou no Blog ou em qualquer outro modelo do ActiveRecord.
Kingdon
3

Eu também não chamaria dois muitos ( is_a?e kind_of?são aliases do mesmo método), mas se você quiser ver mais possibilidades, volte sua atenção para o #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
fonte
1
Graças - eu estava realmente pedindo em um sentido geral de "o que em tempo de execução tipo de informação pode ser recolhida em Ruby e como" - e isso proporciona amplos exemplos
Claudiu