提问人:MorboRe' 提问时间:1/1/2019 最后编辑:anothermhMorboRe' 更新时间:1/1/2019 访问量:1270
为什么结构/类的相等性检查不同?
Why equality check for instance of Struct/Class are different?
问:
我不明白结构和类相等检查之间的区别。由于 Struct 和 Class 都从 Kernel 获得 #hash,但它们的行为似乎不同。
我知道instance.hash会为每个类实例产生不同的结果。与类实例 [Foo, Object, Kernel, BasicObject] 相比,Struct 实例具有不同的祖先 [Customer, Struct, Enumerable, Object, Object, Kernel, BasicObject]。究竟是什么原因导致每个 Class 实例具有不同的哈希号
Customer = Struct.new(:name, :phone, :address) do
end
class Foo
def initialize(the_name, phone, address)
@name = the_name
@phone = phone
@address = address
end
end
str_a = Customer.new('bond', 'ring', 'address')
str_b = Customer.new('bond', 'ring', 'address')
foo_a = Foo.new('bond', 'ring', 'address')
foo_b = Foo.new('bond', 'ring', 'address')
p str_a == str_b #true
p foo_a == foo_b #false
p str_a.hash # 4473040617195177332
p str_b.hash # 4473040617195177332
p foo_a.hash # -3118151143418428190
p foo_b.hash # -1042397847400824657
p str_a.method(:hash).owner #Kernel
p foo_a.method(:hash).owner #Kernel
Struct 和 Class 都使用 Kernel 进行hash_number生成。为什么不同的 Class 实例会产生不同的哈希 int,而 Struct 实例会产生相同的哈希 int?
答:
5赞
Jay Dorsey
1/1/2019
#1
我相信你要找的答案可以在 Struct 文档中找到
Equality—Returns true if other has the same struct subclass
and has equal member values (according to Object#==).
您的示例具有相等的成员值 和 ,并且它们具有相同的子类 (),因此与str_a
str_b
Customer
==
与此对比对象文档
Equality — At the Object level, == returns true only if
obj and other are the same object. Typically, this method is
overridden in descendant classes to provide class-specific meaning.
在您的示例中,并且不是同一个对象(因为它们不是同一个实例)foo_a
foo_b
如果你想知道为什么这些不同,我并没有真正回答这个问题。只是行为符合文档的预期。它们实际上没有相同的 ID:
pry >> Bar = Struct.new(:name) do; end
=> Bar < Struct
pry >> x = Bar.new
=> #<Struct:Bar:0x7f8ebca47610
name = nil
pry >> y = Bar.new
=> #<Struct:Bar:0x7f8ebca14058
name = nil
pry >> x.name = "foo"
=> "foo"
pry >> y.name = "foo"
=> "foo"
pry >> x
=> #<Struct:Bar:0x7f8ebca47610
name = "foo"
pry >> y
=> #<Struct:Bar:0x7f8ebca14058
name = "foo"
但是,您会注意到比较是基于属性的,而不是基于对象 ID:
pry >> x == y
=> true
即使对象 ID 不同:
pry >> x.__id__
=> 70125513489160
pry >> y.__id__
=> 70125513383980
评论
0赞
MorboRe'
1/1/2019
我的意思是为什么相同值的类实例的哈希 int 不同,但具有相同值的结构实例的哈希 int 相同?
0赞
MorboRe'
1/1/2019
我认为这种行为很奇怪,因为 Struct 和 Class 都继承了 Kernel #hash,但它们的行为不同。
1赞
Holger Just
1/1/2019
它们不是相同的方法。Struct#hash
是一种不同的(覆盖)方法,用于考虑不同的相等规则。请注意,对象通常不严格用于对象相等,而是用于标识要使用的对象的键,例如作为对象中的键。如果两个对象具有相同的值,则它们将在对象中使用相同的“插槽”。Kernel#hash
hash
Hash
hash
Hash
0赞
Jay Dorsey
1/2/2019
@MorboRe Holger发布的链接和解释是你的哈希问题的答案。如果切换源,则可以看到他们正在从成员值(看起来像什么)构建哈希。这与为什么以不同的方式计算相等性(这就是它的工作方式,因为它根据值计算哈希值)
0赞
MorboRe'
1/3/2019
有趣的是,我尝试了 Struct.new(“N”).method(:hash).owner 来找出 #hash 方法的所有者,然后得到返回值作为内核。我使用来自某个自定义类的实例方法进行了一些测试,但结果证明是我最后一次修改的类。因此,我假设 #owner 返回最后一个被覆盖的类作为结果。由于 Struct 继承自 Emuerable。我想 #hash 在那里被重新定义,因为 Emuerable 的平等测试以相同的方式工作。谢谢解释
评论