`==` 是不是在 Julia 中递归检查结构?好像没有

Posted

技术标签:

【中文标题】`==` 是不是在 Julia 中递归检查结构?好像没有【英文标题】:Does `==` for struct check recursively in Julia ? It seems not`==` 是否在 Julia 中递归检查结构?好像没有 【发布时间】:2020-11-19 10:07:58 【问题描述】:

在检查 Julia 中有关“结构”对象的相等性时,我不理解一种行为。 文档指出:“对于集合,== 通常在所有内容上递归调用,但也可能会考虑其他属性(如数组的形状)”。虽然它似乎是结构,但它被强制转换为 === 或其他东西。 这是一个最小的工作示例:

正如所料:

string1 = String("S")
string2 = String("S")
string1 == string2 

=> 返回真

和:

set1 = Set(["S"])
set2 = Set(["S"])
set1 == set2

=> 返回真


但是!这就是我不明白的:

struct StringStruct
    f::String
end
stringstruct1 = StringStruct("S")  
stringstruct2 = StringStruct("S")  
stringstruct1 == stringstruct2  

=> 返回真

但是:

struct SetStruct  
    f::SetString  
end
setstruct1 = SetStruct(Set(["S"]))
setstruct2 = SetStruct(Set(["S"]))
setstruct1 == setstruct2 

=> 返回错误


在我看来,=== 似乎在结构的元素上进行了测试。

所以我的问题是:== 在结构上测试时的真实行为是什么?它是投 == 还是 === ?如果它像文档所述那样转换==,那么我误解了什么?

【问题讨论】:

附加信息:有一个问题是让结构像你提到的那样递归比较 (github.com/JuliaLang/julia/issues/4648)。不过,它不会出现在任何 Julia 1.X 版本中,因此在自动递归检查成为语言的一部分(如果有的话)之前,它至少会出现在 Julia 2.0 中。 【参考方案1】:

对于structs 默认== 回退到===,例如:

setstruct1 == setstruct2

一样
setstruct1 === setstruct2

所以现在我们来看看=== 的工作方式。并定义为:

确定xy 是否相同,因为没有程序可以区分它们。

(我省略了定义的其余部分,因为我相信这第一句话建立了一个很好的心理模型)。

现在显然 stringstruct1stringstruct2 是无法区分的。它们是不可变的,并且包含在 Julia 中不可变的字符串。特别是它们具有相同的hash 值(这不是一个确定的测试,但在这里是一个很好的心理模型)。

julia> hash(stringstruct1), hash(stringstruct2)
(0x9e0bef39ad32ce56, 0x9e0bef39ad32ce56)

现在setstrict1setstruct2 可以区分了。它们存储不同的集合,尽管在比较时这些集合包含相同的元素,但它们具有不同的存储位置(因此将来它们可以不同 - 简而言之 - 它们是可区分的)。请注意,这些结构具有不同的哈希值:

julia> hash(setstruct1), hash(setstruct2)
(0xe7d0f90913646f29, 0x3b31ce0af9245c64)

现在注意以下几点:

julia> s = Set(["S"])
SetString with 1 element:
  "S"

julia> ss1 = SetStruct(s)
SetStruct(Set(["S"]))

julia> ss2 = SetStruct(s)
SetStruct(Set(["S"]))

julia> ss1 == ss2
true

julia> ss1 === ss2
true

julia> hash(ss1), hash(ss2)
(0x9127f7b72f753361, 0x9127f7b72f753361)

这一次ss1ss2 通过了所有测试,因为它们再次无法区分(如果您更改ss1,那么ss2 会同步更改,因为它们保持相同的Set)。

【讨论】:

太棒了!这是有用的,完整的和清晰的。谢谢!【参考方案2】:

虽然 Bogumil 的回答解释了正在发生的事情,但让我展示如何将您期望的行为带入您的代码。

只需添加以下几行。

abstract type Comparable end
import Base.==
==(a::T, b::T) where T <: Comparable =
    getfield.(Ref(a),fieldnames(T)) == getfield.(Ref(b),fieldnames(T))

现在您可以根据需要使您的结构具有可比性:

struct SetStruct <: Comparable 
    f::SetString  
end

setstruct1 = SetStruct(Set(["S"]))
setstruct2 = SetStruct(Set(["S"]))

测试:

julia> setstruct1  == setstruct2
true

【讨论】:

太棒了!这对于轻松比较结构很有用。谢谢。

以上是关于`==` 是不是在 Julia 中递归检查结构?好像没有的主要内容,如果未能解决你的问题,请参考以下文章

如何检查给定的“方法”对象是不是接受 Julia 0.6 中给定的类型的“元组”?

Julia:数组是不是包含特定的子数组

Julia:抽象类型与类型联合

在 Julia Flux 中评估简单的 RNN

Julia 中是不是存在类似 Python 的 virtualenv?

处理多种类型和数组时如何编写“好”的 Julia 代码(多重分派)