`==` 是不是在 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】:对于struct
s 默认==
回退到===
,例如:
setstruct1 == setstruct2
和
一样setstruct1 === setstruct2
所以现在我们来看看===
的工作方式。并定义为:
确定
x
和y
是否相同,因为没有程序可以区分它们。
(我省略了定义的其余部分,因为我相信这第一句话建立了一个很好的心理模型)。
现在显然 stringstruct1
和 stringstruct2
是无法区分的。它们是不可变的,并且包含在 Julia 中不可变的字符串。特别是它们具有相同的hash
值(这不是一个确定的测试,但在这里是一个很好的心理模型)。
julia> hash(stringstruct1), hash(stringstruct2)
(0x9e0bef39ad32ce56, 0x9e0bef39ad32ce56)
现在setstrict1
和setstruct2
可以区分了。它们存储不同的集合,尽管在比较时这些集合包含相同的元素,但它们具有不同的存储位置(因此将来它们可以不同 - 简而言之 - 它们是可区分的)。请注意,这些结构具有不同的哈希值:
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)
这一次ss1
和ss2
通过了所有测试,因为它们再次无法区分(如果您更改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 中给定的类型的“元组”?