同一数据类型,hash结果却不一样!?

julia> t1.term
Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))

julia> task.senten.term
Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))

julia> hash(t1.term) == hash(task.senten.term)
false

如上两个 Term 都是同一种自定义的数据类型,同样的成员,hash 结果居然不同!!!我没有为自己的自定义数据类型扩展Base.hash(),如果进行分派,应该如何为自定义数据类型扩展 Base.hash() 以使得 hash 结果相同?

代码能完整的打出来吗??

我也想,只是涉及的代码太多了。 :sob: 问题多数出在我没有为自定义的Struct类型扩展 Base.hash() ,但我没找到相关示例 :sob: 不知道怎么扩展。 我尝试整理下代码,尽量能抽出可复现的

我这数据类型里涉及了 Vectordeepcopy后会不会对hash有影响?

abstract type Term end
abstract type Compound <: Term end
abstract type Statement <: Term end

struct Product <: Compound
    comps::Vector{Term}
end

struct Word <: Term
    literal::String
end

struct Inheritance <: Statement
    t1::Term
    t2::Term
end

以上是数据类型定义,我接着又试了试:

julia> a1 = Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))
Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))

julia> a2 = deepcopy(a1)
Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))

julia> hash(a1)
0xcb656deaa853ba50

julia> hash(a2)
0xff771b2c3c5eab2d

结果仍然不同

你可以定义一个结构体来尝试你上面的代码

好像什么数据都能hash

julia> hash([1,2])
0x8fd27f36c41781c8

是的,但是把数组包装一下就不行了

Base.hash(cpd::Compound, h::UInt) = hash(cpd.comps, h)
Base.hash(st::Statement, h::UInt) = hash(st.t1, hash(st.t2, h))

我把可能包含Vector的自定义类型都给反派了 Base.hash() 函数,目前工作良好。

你可能需要自己实现hash函数来判断,在REPL里使用帮助可以看到hash函数里的说明

New types should implement the 2-argument form, typically by calling the 2-argument `hash`
method recursively in order to mix hashes of the contents with each other (and with `h`).
Typically, any type that implements `hash` should also implement its own `==` (hence
`isequal`) to guarantee the property mentioned above. Types supporting subtraction
(operator `-`) should also implement [`widen`](@ref), which is required to hash
values inside heterogeneous arrays.

大致如下:

import Base.hash
function hash(x::Product)
    hash(x.comps)
end
function hash(x::Inheritance)
    hash(x.t1) ⊻ hash(x.t2)
end

julia> a1 = Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))
Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))

julia> a2 = deepcopy(a1)
Inheritance(Product(Term[Word("a"), Word("b")]), Word("b"))

julia> hash(a1)
0xa858c484eaa939fb

julia> hash(a2)
0xa858c484eaa939fb

我不知道这样实现hash函数是否可行,从结果来说没问题。

1 个赞

建议使用2-arguments版本,第二个参数 h 作为混淆 Julia 有其内部实现,比自己用 xor

是的,我好像看到过 hash 是直接计算内存得来的