二元运算符“==”不能应用于两个操作数。

29

我的类使用协议Equatable。这个类看起来像这样:

class Item: Equatable {

    let item: [[Modifications: String]]

    init(item: [[Modifications: String]]) {
        self.item = item
    }
}

func ==(lhs: Item, rhs: Item) -> Bool {
    return lhs.item == rhs.item
}
但是这会给我带来错误(见标题)。属性item之前是[[String: String]],没有问题,我不知道该如何解决。我尝试在谷歌和SO上搜索,但没有运气。
枚举只是一个简单的基本枚举:
enum Modifications: Int {
    case Add    = 1
    case Remove = 2
    case More   = 3
    case Less   = 4
}

也许你需要将 == 函数放在类定义内部,以使其符合 Equatable 协议。 - dudeman
@MikeAtNobel 不,实现的位置很好。 - milo526
修改是否符合可比性?由于您在字典数组中使用它,我可以理解为什么需要使其可比性以使您的项目可比性。 - milo526
当它是 [[String: String]] 时,没有问题,所以应该能够比较2D字典。@milo526:因为枚举具有原始类型值,所以如果我没错的话,它会自动变成可比较的。@Leo Dabus:是的,我正在尝试想出另一种方法,但如果它是一个字典数组,那将会更容易。 - Henny Lee
它外观上与https://dev59.com/4VwX5IYBdhLWcg3wySB1类似:您*可以*使用“==”比较两个`[Modifications:String]`实例,但是`[Modifications:String]`不符合`可比较协议`。因此,对于这些字典的*数组*未定义“==”。 - 我的猜测是它适用于[[String:String]],因为[String:String]可以桥接到NSDictionary(再次可比较)。 - Martin R
是的,问题在于字典数组的类型为[Modifications: String]。我猜我仍然可以使用[[String: String],但使用“Modifications.description”作为键。不过我希望能够解决这个问题... - Henny Lee
2个回答

27

更新: SE-0143 条件一致性 已在 Swift 4.2 中实现。

因此,您的代码现在可以编译。如果您将 Item 定义为 结构体

struct Item: Equatable {
    let item: [[Modifications: String]]

    init(item: [[Modifications: String]]) {
        self.item = item
    }
}

然后编译器会自动合成==运算符,比较SE-0185 Synthesizing Equatable and Hashable conformance


(Swift 4.1之前的回答:)

问题在于即使为字典类型[Modifications: String]定义了==,该类型也不符合Equatable。因此,数组比较运算符

public func ==<Element : Equatable>(lhs: [Element], rhs: [Element]) -> Bool

无法应用于[[修改:字符串]]

Item的可能简洁实现==是:

func ==(lhs: Item, rhs: Item) -> Bool {
    return lhs.item.count == rhs.item.count 
           && !zip(lhs.item, rhs.item).contains {$0 != $1 }
}

如果导入了Foundation框架,您的代码将编译通过[[String: String]],就像@user3441734正确指出的那样。因为[String: String]会自动转换为符合EquatableNSDictionary。以下是该声明的“证明”:

func foo<T : Equatable>(obj :[T]) {
    print(obj.dynamicType)
}

// This does not compile:
foo( [[Modifications: String]]() )

// This compiles, and the output is "Array<NSDictionary>":
foo( [[String: String]]() )

很好的解释,知道为什么[[String: String]]可以工作是很好的。因为答案看起来更优雅,所以将其标记为已回答。现在我只需要想出如何忽略字典的顺序。 - Henny Lee
@MartinR:在我下面的答案中,user3441734在评论中指出Dictionary类型不符合协议Equatable。你不知道我们为什么仍然可以“立即”比较它们,就像上面的$0 != $1(或者在我的解决方案中的lhsDict != rhs.item[i])吗?这是一些自动转换,就像你上面提到的情况一样吗? - dfrib
@dfri:有一个public func ==<Key : Equatable, Value : Equatable>(lhs: [Key : Value], rhs: [Key : Value]) -> Bool运算符:如果键和值类型都是可比较的,则可以使用==比较字典。这与数组相同:如果元素类型是可比较的,则可以使用==比较它们。 - Martin R
@MartinR 请注意,使用Foundation的帮助可以实现“自由桥接”。顺便说一下,您的解释非常清晰!我希望我也有同样的能力来表达我的想法或观点。不幸的是,我没有... - user3441734
@user3441734:你说得完全正确,那是一个很好的观点。 - Martin R

3
在你的==函数中,针对Item对象,需要进一步指定如何比较两种字典数组类型(具体而言是两种[[Modifications: String]])。
下面是一个可行的解决方案:按元素(即按字典)逐个比较你的item数组,并且==仅当数组包含相同数量的字典并且所有条目都相同且以相同的方式在字典数组中排序时才返回true。
func ==(lhs: Item, rhs: Item) -> Bool {

    if lhs.item.count == rhs.item.count {
        for (i, lhsDict) in lhs.item.enumerate() {
            if lhsDict != rhs.item[i] {
                return false
            }
        }
        return true
    }
    else {
        return false
    }
}

class Item : Equatable {

    let item: [[Modifications: String]]

    init(item: [[Modifications: String]]) {
        self.item = item
    }
}

您可能希望将此修改为实际要用于比较的形式,但我希望您能理解其要点。

还要注意,如果在游乐场中测试此代码,请确保您的==函数定义func ==(lhs: Item, rhs: Item) -> Bool { ..应该您的类定义之前,否则您将会得到一个不符合Equatable的错误。


谢谢,这确实使Item可比较。虽然我希望有更简单的方法,但我想我必须遍历数组并进行比较。 - Henny Lee
@HennyLee 也许你能提出一个更好的解决方案,这个例子主要展示了如何实现一个_可工作的_解决方案。例如,使用zipmap可以将循环压缩成一行,前提是数组长度相同。 - dfrib
Swift数组不符合可比协议。因此,你需要让Array<[Modification:String]>符合可比协议。如何实现取决于你。符合可比协议意味着定义了运算符==。如果你愿意,它可以简单地返回true :-) 检查类型[Modifications:String]的实例的方式完全由你负责。 - user3441734
@user3441734,你说得很对,只是要注意两个类型为[Modifications:String]的字典可以直接使用==进行比较(因为字典是可比较的):这里的问题是这些字典的数组具有非基本键类型(正如Martin R在他的答案中所涵盖的)。 - dfrib
@dfri 你确定 Dictionary 符合 Equatable 协议吗? - user3441734
@user3441734,你说得对。看起来 Dictionary 没有遵循 Equatable 协议,所以这些字典可以使用 == 的原因可能是自动转换,而不是遵循 Equatable 协议的结果。 - dfrib

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