Ruby:kind_of?与instance_of?与is_a?

565

区别在哪里?我应该使用哪种?为什么有这么多种?


24
为什么is_a?kind_of?都存在呢?我想这是 Ruby 设计哲学的一部分。Python 会说应该只有一种做法;Ruby 经常有同义词方法,这样你就可以使用听起来更好的那个。这是个人喜好的问题。这可能部分是由于日本的影响:据说他们会根据句子使用不同的字来表示同样的数字,以使其听起来更好听。Matz 可能已经将这个想法带入了他的语言设计中。 - Nathan Long
@NathanLong 我认为日语计数器与此并没有太大关系;所有语言都有某种形式的一致性,你不能大多数情况下替换一个计数器来代替另一个(比如,你不能用圆柱体计数器来计算平面物体;这是错误的)。这更多地涉及语义而不是音韵美。 - Casey
7
@Casey,Nathan可能是指的"四"这个数字,在日语中可以读作"shi"和"yon"。有时候日语使用者会避免发音为"shi"的读音,因为它与"死"(death)谐音。例如,请参阅此Omniglot文章:“在日语中,4和9被认为是不吉利的数字:4读作"shi",听起来像"死"(death)一词,而9读作"ku",听起来像"苦"(suffering)一词。因此,它们通常会读作"yon"和"kyu"。” - RubyTuesdayDONO
@RubyTuesdayDONO,这并不是要避免这种关联;在许多情况下,只有其中一个是正确的,你不能随意替换。 - Casey
5个回答

721

kind_of?is_a? 是同义词。

instance_of? 与另外两个不同,它只有在对象是该类的实例而不是子类时才返回true

例如:

  • "hello".is_a? Object"hello".kind_of? Object 返回true,因为"hello" 是一个String类型,StringObject的子类。
  • 但是 "hello".instance_of? Object 返回false

91
有时候简单的表达更加清晰易懂,像 @honda.kind_of? Car@person.is_a? Administrator,Ruby非常讲究美感。事实上,注意到了语法错误...使用active support 你可以写成 @person.is_an? Administrator :)...其实这也许已经被加入到Ruby核心部分了。 - rfunduk
3
这个原因很有趣。你能详细说明一下吗?比如说,你能覆盖 kind_of? 但不能覆盖 is_a? 吗? - Claudiu
4
@thenduks,“is_an?”在ruby-1.9.2-p0中不存在。@Claudiu,不是的。is_a?只是kind_of?的别名。这两个方法调用相同的C函数rb_obj_is_kind_of - ma11hew28
10
@Matt:您可以重写别名而不必重写已别名的函数。因此,是的,您可以重写 kind_of? 而不必重写 is_a? - sepp2k
5
这个 is_an? 方法在哪里?它不在当前的 Rails 版本中,而且我在 Google 上也找不到任何有关它被弃用的信息。请问这个方法去哪儿了? - Tom Lord
显示剩余6条评论

25

区别在哪里?

根据文档:

- (Boolean) instance_of?(class)
如果obj是给定类的实例,则返回true

和:

- (Boolean) is_a?(class)
- (Boolean) kind_of?(class)
如果classobj的类,或者classobj的超类之一或包含在obj中的模块,则返回true

如果这不清楚,最好知道是什么不清楚,以便改进文档。

我应该使用哪个?

从不。改用多态性。

为什么会有这么多?

我不会说两个是“很多”。有两个,因为它们做两件不同的事情。


5
我觉得我现在感到困惑的原因是有3种东西,其中2种只是做同样的事情但有不同的名称。关于使用多态性 - 我同意,但Ruby标准库中充满了对这些东西的每种方式的使用。 - Claudiu
4
多态是什么意思?它与鸭子类型相同吗? - Andrew Grimm
2
是的,它们是相同的。鸭子类型是一种多态形式。 - SpaceGhost
3
通常情况下,使用多态是更好的选择,但有一些边缘情况需要确切知道你正在处理的特定类别,比如处理文件时。 - Automatico

9

更符合Ruby的风格是使用respond_to?来询问对象是否响应你需要的方法,这样既可以实现最小接口,也可以实现无需知道具体实现的编程。

当然,并不总是适用,因此仍然有可能通过所要询问的方法来询问更保守的“类型”理解,即类或基类。


9
视情况而定。评论和博客都可能响应“created_at”(创建时间)。在这种情况下,我认为“is_a?”更加合适。 - penkovsky
这并没有意义,如果你需要区分评论和博客对象,你就不会使用created_at来做到这一点。这并不排除你可以编写一个方法,该方法接受一个响应created_at的对象。如果它不需要其他任何东西来完成工作,那么你可以安全地在评论或博客上使用它,或者几乎在任何其他ActiveRecord模型上使用它。 - Kingdon

5

我并不认为使用两个方法 (is_a?kind_of? 是同一个方法的别名) 就是太多,但如果您想看到更多可能性,请关注# class 方法:

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

1
谢谢 - 我确实是在一般意义上询问“Ruby中可以收集哪些运行时类型信息以及如何收集”,这提供了充足的示例。 - Claudiu
何时最好使用 .class 而不是 .instance_of? - Ridhwaan Shakeel

0

https://dev59.com/a2865IYBdhLWcg3wSMgw#3893305是一个很好的解释...为了更加详细地说明,我倾向于使用is_a?来判断“原始类型”(String、Array、可能是Hash等)

所以"hello".is_a?(String)[].is_a?(Array){}.is_a?(Hash)

对于其他任何东西,我倾向于使用instance_of? (Animal.new.instance_of?(Animal)

我说“倾向于”,因为情况并不是那么明确。例如:

class Animal;end

class Dog < Animal;end

x = Dog.new

x.is_a?(Dog) # => true
x.is_a?(Animal) # => true
x.instance_of?(Dog) # => true
x.instance_of?(Animal) # => false

正如你所看到的,x 同时是 Dog 和 Animal,但它只是 Dog 的一个实例。

我认为这是一个特定性问题:

  • 如果我只想知道它是一个 Animal 而不是 Plant,我会使用 is_a?。
  • 如果我关心它是一只狗而不是一只猫,我会使用 instance_of?。

然后你可以进一步细化。如果我关心它是 Sighthound 而不是 Bloodhound,假设两者都是 Dog 的子类。那么我可能希望更加具体。

话虽如此,is_a?(Animal|Dog|Sighthound) 总是有效的。但如果你关心具体的子类,instance_of? 总是更加具体。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接