Ruby 详解 Ruby 里用到的比较函数 (equal?, eql?, ==, ===)

wongyouth · 2014年07月05日 · 最后由 lionzixuanyuan 回复于 2014年07月07日 · 4945 次阅读

Ruby 里面有 4 种比较方法,equal?, eql?, ==, ===,而且在不同的类里面表现的很不一样。在使用的时候也特别容易搞糊涂。 这篇博文将演示一些代码来讲解各个方法。

== - 类意义上的 相等,需要每个类自己定义实现

在特定类中觉得两个对象是否相同,需要看业务上的逻辑表象,所有由程序员覆盖该方法的定义,决定两个对象是否相同。

比如 String 类,他是来计较实际的文字串是否相同,而不在意是否来自同一个内存区域。

>> a = "abc"
#=> "abc"

>> b = a + ""
#=> "abc"

?> a == b
#=> true

>> a.object_id
#=> 70255156346640

>> b.object_id
#=> 70255156340640

=== - 用在 case 语句里时会调用的方法

通常用在 case 比较调用该方法,比如

case some_object
when /a regex/
  # The regex matches
when 2..4
  # some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
  # the lambda returned true
end

等同于

if /a regex/ === some_object
  # The regex matches
elsif (2..4) === some_object
  # some_object is in the range 2..4
elsif lambda {|x| some_crazy_custom_predicate } === some_object
  # the lambda returned true
end

eql? - 通常意义上的 相等

如果两个对象的值相同将返回 true,如果重新定义了子类的 == 方法,一般需要 alias 到 eql? 方法。 当然也有例外,整数与小数的比较两个方法的返回值就不同。

1 == 1.0   #=> true
1.eql? 1.0 #=> false

eql? 用在 Hash 里面用来做成员值比较

[1] pry(main)> hash = Hash.new
#=> {}
[2] pry(main)> hash[2] = "a"
#=> "a"
[3] pry(main)> hash[2.0] = "b"
#=> "b"
[4] pry(main)> hash[2]
#=> "a"
[5] pry(main)> hash[2.0]
#=> "b"
[6] pry(main)> hash[2.00] = "c"
#=> "c"
[7] pry(main)> hash[2.0]
#=> "c"

所以什么时候应该覆盖这个方法就看你想让他在 Hash 比较时如何表现。

equal? - 内存地址相同的对象

  • 该方法不应该被子类覆盖
  • 比较的是两个对象在内存中是否相同,是否有同一个object_id
  • Rails 中及时相同的对象
q = User.first
  User Load (40.4ms)  SELECT  "users".* FROM "users"   ORDER BY "users"."id" ASC LIMIT 1
#=> #<User id: 1, email: "[email protected]">

q2 = User.first
  User Load (0.4ms)  SELECT  "users".* FROM "users"   ORDER BY "users"."id" ASC LIMIT 1
#=> #<User id: 1, email: "[email protected]">

q.equal? q2
#=> false

记忆方法

  • == 按业务需求覆盖该方法
  • === 覆盖 case 语句时的表现
  • eql? 别名到 == 方法, 需要时覆盖方法改变 Hash 比较时的表现
  • equal? 不改动

延伸阅读

http://stackoverflow.com/questions/7156955/whats-the-difference-between-equal-eql-and

首发在这里 http://wongyouth.com/blog/2014/07/05/variations-of-equal-method-in-ruby/

想对===稍微做一点补充 一开始我也没明白这东西到底是干嘛的

为什么有==还要有=== 用 regex 和 string 来举个栗子,regex 不是 string, string 也不是 regex,所以我们肯定不希望 string == regex

/xiaopingguo.*/ =~ 'xiaopingguo'  # :)
/xiaopingguo.*/ == 'xiaopingguo'  # :(

所以在使用 case 时,regex 会调用===来匹配 string,这样代码看起来简洁且易懂。

还有一点是对于 class 来说===kind_of?是 alias

the_little_apple = "小苹果"

case the_little_apple
when String
  puts "string"
when Fixnum
  puts 2
end

#2 楼 @leozwa 嗯,在看帖子中的内容时也想到了这点,还是@ShiningRay给我讲解的,印象深刻

mingyuan0715 ==, eql? , === 核心类 Override 一览表 提及了此话题。 05月05日 21:00
需要 登录 后方可回复, 如果你还没有账号请 注册新账号