ruby - 带有自定义类的 Ruby Set 等于基本字符串
问题描述
我希望能够在我的集合中找到一个自定义类,只需一个字符串。像这样:
require 'set'
Rank = Struct.new(:name, keyword_init: true) {
def hash
name.hash
end
def eql?(other)
hash == other.hash
end
def ==(other)
hash == other.hash
end
}
one = Rank.new(name: "one")
two = Rank.new(name: "two")
set = Set[one, two]
但是 whileone == "one"
和one.eql?("one")
都是真的,set.include?("one")
仍然是假的。我错过了什么?
谢谢!
解决方案
Set
建立在 之上Hash
,并且在以下情况下Hash
认为两个对象相同:
[...] 它们的
hash
值是相同的,并且这两个对象是eql?
相互关联的。
你缺少的是那eql?
不一定是可交换的。识别Rank#eql?
字符串不会改变工作方式String#eql?
:
one.eql?('one') #=> true
'one'.eql?(one) #=> false
因此,它取决于哪个对象是散列键,哪个是 的参数include?
:
Set['one'].include?(one) #=> true
Set[one].include?('one') #=> false
为了制作两个对象a
和b
可互换的哈希键,必须满足 3 个条件:
a.hash == b.hash
a.eql?(b) == true
b.eql?(a) == true
但是不要尝试修改String#eql?
——不建议摆弄 Ruby 的核心类,而且猴子补丁可能无论如何也不起作用,因为 Ruby 通常出于性能原因直接调用 C 方法。
事实上,一开始就同时制作hash
和eql?
模仿name
似乎不是一个好主意。它使对象的身份模棱两可,这可能导致非常奇怪的行为并且难以找到错误:
h = { one => 1, 'one' => 1 }
#=> {#<struct Rank name="one">=>1, "one"=>1}
# vs
h = { 'one' => 1, one => 1 }
#=> {"one"=>1}
推荐阅读
- python - 在字典中添加数组值
- excel - Excel VBA 代码过滤特定列并从其他列中删除数据
- python - 使用 Python OpenCV 在模糊对象周围寻找紧密轮廓
- linux - 在 shell 脚本中存储 plsql 查询的输出
- android-studio - 如何停止 Android Studio 3.6 生成新片段
- python - subprocess.call() 给出“系统找不到指定的路径。” 当文件存在并且可以真正运行时
- r - 在 R 中格式化电子表格时出现问题,如何使用 R 读取和写入表?
- python - 比较四个字典,它们的键相同但每个字典在 python 中都有不同的值
- java - 中序遍历是否可能与后序遍历相同?
- javascript - 在确认 Javascript 中单击“取消”按钮时页面仍会重新加载