考虑 Swift 5.9 中的这个协议和类:
protocol SpinnerHosting: AnyObject
{
var spinnerItem: SpinnerItem { get }
}
final class MyViewController: NSViewController
{
var activeChild: (NSViewController & SpinnerHosting)? = nil
func pushChild(_ incomingChild: (NSViewController & SpinnerHosting))
{
// #1
if incomingChild != activeChild {
...
}
// #2
if incomingChild != activeChild! {
...
}
}
}
在第 1 点,Swift 抛出了这个错误:
Type 'any NSViewController & SpinnerHosting' cannot conform to 'Equatable'
在第 2 点(忽略不安全的展开)它会抛出这个:
Binary operator '!=' cannot be applied to two 'any NSViewController & SpinnerHosting' operands
我明白为什么协议不是
Equatable
。但我不明白为什么编译器认为这不是。在这里,SpinnerHosting
被限制为 AnyObject
,这意味着引用类型,因此意味着指针相等。但是,如果我将协议限制为 NSViewController
本身,同样的错误仍然存在,这 绝对 让我感到惊讶,因为 NSViewController
是相等的。
我只是想说:“无论
NSViewController
占据 activeChild
,都必须具有 spinnerItem
属性。” (我意识到我可以用子类来做到这一点;这不是我的问题。)
我刚刚在几个 Apple 源示例中看到了这种模式:
var foo: ([Class] & [Protocol])
,但我没有看到为什么这不能是 Equatable
的充分理由。
所有引用类型都“与
==
一起使用”来比较指针,这是真的,但并非所有引用类型都声明与 Equatable
一致。
编译器不会通过查找协议声明的所有方法、属性和运算符来检查一致性;它只是检查声明的类型是否是协议或符合协议。
换句话说,即使类型有运算符
==
,也不意味着它可以转换为Equatable
:必须显式声明一致性。