Swift:NSViewController与协议组合类型无法使用Equatable的问题
为什么类+协议组合类型无法使用Equatable?
在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 报错:`Type 'any NSViewController & SpinnerHosting' cannot conform to 'Equatable'` if incomingChild != activeChild { ... } // #2 报错:`Binary operator '!=' cannot be applied to two 'any NSViewController & SpinnerHosting' operands` if incomingChild != activeChild! { ... } } }
核心原因
虽然NSViewController本身遵循Equatable,且SpinnerHosting约束了AnyObject(引用类型本来可以靠指针判断相等),但这里的NSViewController & SpinnerHosting属于existential类型(也就是Swift 5.7+里的any类型),这类组合类型不会自动继承类的Equatable实现。
具体来说:
- 当你用
NSViewController & SpinnerHosting作为变量或参数类型时,Swift会把它当成一个容器,既包含NSViewController的所有特性,又满足SpinnerHosting的协议要求。 - 哪怕底层类型是
Equatable的类,existential类型本身需要明确声明遵循Equatable才能使用==或!=。但由于SpinnerHosting是协议,Swift没办法自动给这种类+协议的组合类型合成Equatable实现——它不会默认把类的Equatable实现“传递”给组合后的existential类型。
临时解决方法(针对引用相等需求)
如果你的需求只是判断两个对象是不是同一个实例(指针相等),可以直接用===操作符替代!=:
- 针对#1的可选类型:
if incomingChild !== activeChild { // ... } - 针对#2的解包后类型:
if incomingChild !== activeChild! { // ... }
因为AnyObject约束的类型都支持===,刚好满足引用类型的相等判断需求。
内容的提问来源于stack exchange,提问作者Bryan
相关产品推荐
相关产品推荐

