如何将泛型类型引用为其继承的父协议类型?
泛型存储协议的可变/只读类型兼容问题解决方案
你的现有协议继承结构完全可以实现需求,不需要取消继承改用关联类型。核心思路是利用MutableStorage继承自ImmutableStorage的特性,通过**存在类型(any)**或泛型约束,让collectItems方法的闭包参数接受只读的ImmutableStorage类型,同时保证类型匹配。
修改后的代码示例
调整collectItems方法的签名,将闭包参数类型改为与当前存储同StorageItem的ImmutableStorage存在类型:
class StorageExample<S: MutableStorage> { private var mutableStorage: S init(mutableStorage: S) { self.mutableStorage = mutableStorage } // 调整闭包参数为只读的ImmutableStorage类型,约束StorageItem与S一致 func collectItems(_ collector: (any ImmutableStorage where StorageItem == S.StorageItem) -> [S.StorageItem]) { let itemUpdates = collector(mutableStorage) // 可直接传入,因为S遵循ImmutableStorage for item in itemUpdates { mutableStorage.contents[item.key] = item } } } /// 可读写的存储协议 protocol MutableStorage: ImmutableStorage { var contents: [StorageItem.Key: StorageItem] { get set } } /// 只读存储协议(仅可查看,不可修改) protocol ImmutableStorage { associatedtype StorageItem: Item var contents: [StorageItem.Key: StorageItem] { get } } /// 可被存储的Item协议 protocol Item { associatedtype Key: Hashable associatedtype Data var key: Key { get } var data: Data { get } }
关键说明
- 类型兼容性:由于
MutableStorage继承自ImmutableStorage,S类型的实例天然符合ImmutableStorage协议,因此可以直接传入接受ImmutableStorage的闭包。 - 存在类型的作用:
any ImmutableStorage where StorageItem == S.StorageItem确保闭包只能访问存储的只读接口,同时约束存储的StorageItem类型与当前类的泛型参数一致,避免类型不匹配。 - 语义保留:当前的继承关系清晰表达了“可变存储是只读存储的扩展”这一语义,相比改用关联类型,更符合面向协议设计的原则,也更易维护。
如果需要兼容Swift 5.7以下版本(不支持any关键字),可以改用泛型方法实现相同效果:
func collectItems<I: ImmutableStorage>(_ collector: (I) -> [S.StorageItem]) where I.StorageItem == S.StorageItem { guard let immutableStorage = mutableStorage as? I else { fatalError("存储类型不匹配") } let itemUpdates = collector(immutableStorage) for item in itemUpdates { mutableStorage.contents[item.key] = item } }
内容的提问来源于stack exchange,提问作者zekel
相关产品推荐
相关产品推荐

