任何人都可以解释一下,这是怎么回事:
struct Test {
var value: Int
}
// -----------------------------------
protocol Test1: Equatable {
var value: Int { get set }
}
extension Test1 {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.value == rhs.value + 1
}
}
// -----------------------------------
protocol Test2: Equatable {
var value: Int { get set }
}
extension Test2 {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.value == rhs.value + 2
}
}
// -----------------------------------
extension Test: Test1 {}
extension Test: Test2 {}
let a = Test(value: 5)
let b = Test(value: 5)
print(a == b) // true, which is unexpected
如果仅符合Test1
或仅符合Test2
,则按预期工作。
符合Test1
和Test2
。起初,我认为顺序很重要。但是看起来它只是互相抵消了!没有任何警告。这很违反直觉。
答案 0 :(得分:3)
注意: Test
符合Equatable
不是,因为您提供了两个扩展名,但由于自动生成的{{1 }}实现。如您所说,如果只有这两个扩展名,那么Equatable
是==
的实现将是不确定的。
Equatable
或==
协议扩展中的Test1
都不被调用。而是调用自动生成的Test2
实现。您可能还记得,Equatable
运算符是为属性均为==
的类型自动生成的,并声明为符合Equatable
本身。
这是因为扩展中声明的成员使用静态绑定,因此,当同一成员有多个版本可用时,仅当编译时类型是扩展的类型时才选择扩展中声明的版本。例如:
Equatable
在protocol P { }
class C : P { func f() { print("C") } }
extension P { func f() { print("P") } }
C().f() // C
(C() as P).f() // P
中,a == b
和a
均为b
,因此没有选择任何扩展运算符。但是,由于Test
和Test1
都使用Test2
,因此您只能将它们用作一般约束,也不能强制转换为约束。因此,我认为您根本无法调用扩展名中声明的Self
。
无论如何,如果您想看到一条错误消息,指出存在重复的==
个运算符:
==
错误:“测试”类型与协议“ Equatable”扩展名不符 测试:Test1 {} ^
注意:候选人完全匹配
struct Test { var value: Int var x: Any? // now there is no auto-generated Equatable implementation! }
注意:候选人完全匹配
static func == (lhs: Self, rhs: Self) -> Bool { ^
如果您删除其中一个扩展名,则由于扩展名的存在, static func == (lhs: Self, rhs: Self) -> Bool {
^
符合Test
,因为不再有歧义。因此,自动生成的实现不再自动生成,只有一个Equatable
可供选择-扩展中声明的实现。