使用数组的结构体比较

8
如果我在一个结构体中有如下数组,那么我不能比较结构体的相等性,因为这些数组是可变的。有没有办法使相等性传递到数组中,以便我得到 `a([1,2,3]) == a([1,2,3])` 的结果为 `true`?或者唯一的方法是扩展 `Base.==` 吗?
julia> struct a
       v
       end

julia> a([1,2,3]) == a([1,2,3])
false

julia> a(1) == a(1)
true

julia> [1,2,3] == [1,2,3] # want the equality to work like this for the struct
true

julia> [1,2,3] === [1,2,3]
false
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
11
@miguel raz的答案根本不起作用! 这是因为isequal实际上调用的是==而不是==调用isequal。在isequal文档中,您可以明确找到以下内容: “isequal的默认实现调用==,因此通常只需要定义涉及非浮点值的类型的==。” 因此,正确的代码应该是:
struct A
  v
end
import Base.==
==(x::A,y::A) = x.v==y.v

然而,更加优美的方法是编写一个通用代码,不依赖于字段v。由于我们不想重载默认的==运算符,我们可以定义一个abstract类型,告诉Julia使用我们的实现:

abstract type Comparable end

import Base.==

function ==(a::T, b::T) where T <: Comparable
    f = fieldnames(T)
    getfield.(Ref(a),f) == getfield.(Ref(b),f)
end
现在您可以定义自己的结构体并进行正确比较:
struct B <: Comparable
    x
    y
end

测试:

julia> b1 = B([1,2],[B(7,[1])]);

julia> b2 = B([1,2],[B(7,[1])])

julia> b1 == b2
true

这很好,尽管看起来你正在像类型类一样使用Julia的继承。如果原始结构已经有一个基类会发生什么? - dividebyzero
不幸的是,Julia不支持多重继承,因此您需要定义类似于function ==(a::T, b::T) where T <: Union{Comparable,SomeOtherType}这样的内容。 - Przemyslaw Szufel

3

如@Przemyslaw所述,需要重载==操作符。
对于抽象类实现无法满足的情况,可以将重载实现为一行代码(避免使用import语句):

Base.:(==)(a::A, b::A) = Base.:(==)(a.v, a.v)

对于不需要特殊NaN和missing值语义的结构体,覆盖isequal函数也是一种好方法,同时对于可以用作键的结构体,覆盖hash函数也很重要:

Base.isequal(a::A, b::A) = Base.isequal(a.v, b.v)
Base.hash(a::A, h::UInt) = Base.hash(a.v, h)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,