1、kind_of?, is_a?, instance_of? 的区别
obj.kind_of? (klass) -> true or false
判断klass是否是obj的类,或者超类,或者被mixin的模块
obj.is_a? (klass) -> true or false
和kind_of? 一样
obj.instance_of? (klass) -> true of false
判断obj是否是由klass生成的实例
测试代码:
module Mother; end class Father include Mother end class Son < Father; end son = Son.new son.kind_of? Son # true son.kind_of? Father # true son.kind_of? Mother # true son.is_a? Mother # true son.instance_of? Son # true son.instance_of? Father # false son.instance_of? Mother # false
2、==, ===, equal?, eql? 的区别
这四个方法可以说都有细节区别,但从效果可以粗略地分为两类,一是比较两者是不是引用自同一个对象,二是比较两者的值是否相同。
obj == other_obj -> true or false
在Object类层面,这个方法是判断obj和 other_obj是不是同一个对象(可以理解为两者的object_id一定要相同)。但通常子类都会重写 == 方法来加入自己的比较逻辑。虽然每个子类都对此有不同的实现,但常见的作用就是比较两个对象的值是否相同。
obj === other_obj -> true or false
主要用于case语句中的比较。效果和 == 一样,但一般会被子类重写,来适应case语句的需要。很典型的就是正则表达式的 === 方法。
obj.equal? (other_obj) -> true or false
判断obj和other_obj的object_id是否相同。子类不会重写这个方法。所以它的效果在任何对象中都是一样的
obj.eql? (other_obj) -> true or false
判断obj和other_obj的值是否相同。和 == 差不多,但有些细微区别,比如Numeric类型,1.eql?(1.0) 是返回 false 的,因为两者类型不同,而 == 则会做类型转换再比较。
测试代码:
ary1 = %w{cat dog} ary2 = %w{cat dog} # 测试 == ary1 == ary2 # true 1 == 1.0 # true # 测试 equal? ary1.equal? ary2 # false 1.equal? 1 # true 相同的整型数的object_id也相同,这点和Symbol类似 # 测试eql? ary1.eql? ary2 # true 1.eql? 1 # true 1.eql? 1.0 # false 类型不同 # 测试 === /string/ == "string" # false /string/ === "string" # true 为了case语句的比较而改写了Regexp的===方法 Symbol.class_eval do # 改写Symbol的===方法,使之可以等于相同“内容”的字符串 def ===(value) value.is_a?(String) ? self.to_s == value : super end end case "string" when :string # 这里就会调用:string === "string",成功匹配 true else false end
3、Array#to_a, Array#to_ary 的区别
这里只以 Array 的对象来作比较。因为只有这个类同时实现了这两个方法。从作用而言,它们都是返回一个和原数组内容相同的数组。但细节还是有区别的。
arr.to_ary -> ary
这个方法很简单,直接返回方法调用者。返回值和原对象没有区别。
arr.to_a -> arr
这个方法复杂一点。首先,当arr是Array的实例时,直接返回arr;当arr是Array子类的实例时,会先使用 to_ary 获得一个数组,然后根据这个数组创建一个新数组(就是复制)返回。
测试代码:
a = [1, 2, 3] a.to_a.equal? a # true 因为就是返回自身 a.to_ary.equal? a # true class SubArray < Array; end b = SubArray.new b.to_a.equal? b # false 因为是Array的子类,所以新数组是复制过的 b.to_ary.equal? b # true