You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Swift协议实现观察者模式遇Hashable报错如何解决?

错误原因

你遇到的报错是Swift的经典限制:协议本身无法直接遵从协议,哪怕你已经给P协议添加了Hashable的默认实现,直接将P作为类型声明Set<P>时,编译器依然会判定协议类型P没有满足Hashable的遵从要求。

解决方案

方案1:使用类型擦除包装类(兼容所有Swift版本)

这是最通用的解决方案,我们可以定义一个包装类来抹掉具体实现类型的差异,同时满足Hashable要求:

class AnyP: P {
    private let wrapped: P
    private let notifyBlock: () -> Void

    init<T: P>(_ value: T) {
        self.wrapped = value
        self.notifyBlock = value.notify
    }

    func notify() {
        notifyBlock()
    }

    static func == (lhs: AnyP, rhs: AnyP) -> Bool {
        ObjectIdentifier(lhs.wrapped) == ObjectIdentifier(rhs.wrapped)
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(ObjectIdentifier(wrapped))
    }
}

使用方式修改为:

var set: Set<AnyP> = [AnyP(Implementation1()), AnyP(Implementation2())]
for x in set {
    x.notify()
}

方案2:使用Swift 5.7+ 新特性(适合高版本部署目标)

如果你的项目部署目标支持Swift 5.7(iOS 16+/macOS 13+/watchOS 9+/tvOS 16+),可以直接用any关键字声明存在类型,编译器会自动处理协议遵从:

// 仅需修改Set的声明即可,其余代码无需改动
var set: Set<any P> = [Implementation1(), Implementation2()]
for x in set {
    x.notify()
}

方案3:改用数组存储(轻量场景首选)

观察者模式通常不需要Set的去重特性,就算需要去重也可以自己手动实现引用判断,完全可以用数组代替Set规避协议遵从问题:

var observers: [P] = []

// 添加观察者时手动去重
func addObserver(_ observer: P) {
    guard !observers.contains(where: { $0 === observer }) else { return }
    observers.append(observer)
}

// 触发通知
observers.forEach { $0.notify() }

这种方案不需要修改原有协议和实现类,还能保证观察者的触发顺序,是多数观察者模式实现的首选方案。

内容的提问来源于stack exchange,提问作者user16889355

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:51:00