Swift中为何无法将继承其他协议的协议作为泛型参数?
问题分析与解答
核心误区
你混淆了「所有遵循Labelled的具体类型都符合Hashable」和「any Labelled这个存在类型本身符合Hashable」这两个概念。
为什么编译报错?
Hashable继承自Equatable,而Equatable的核心方法static func == (lhs: Self, rhs: Self)带有Self约束——这个约束要求比较的两个实例必须是同一个具体类型。
当你写Storage<Labelled>时,Swift会自动推断为Storage<any Labelled>(存在类型),而any Labelled可以包裹任意遵循Labelled的具体类型实例。此时如果要让any Labelled符合Hashable,就必须保证两个any Labelled实例能正确执行==比较,但这做不到:比如一个包裹TypeA实例,另一个包裹TypeB实例,它们根本不是同类型,无法满足Equatable的Self约束。
所以Swift明确禁止这种用法,报错提示「Type 'any Labelled' cannot conform to 'Hashable'」。
为什么去掉Hashable约束后能编译?
当你把Storage<V: Hashable>改成Storage<V>时,泛型参数V不再需要满足Hashable约束,此时Storage<any Labelled>只是存储一个类型擦除的协议实例,不需要它支持哈希或相等比较,自然就没有问题。
解决办法
如果需要保留Storage的Hashable约束,你有两种选择:
- 使用具体类型而非存在类型:比如定义一个遵循
Labelled的具体类型,然后声明let storage: Storage<MyConcreteType> - 调整协议设计:如果一定要用存在类型,需要放弃对
V的Hashable约束,或者在业务逻辑中手动处理哈希/相等比较(比如给Labelled协议添加自定义的哈希方法,而非依赖Swift自动合成的Hashable实现)
内容的提问来源于stack exchange,提问作者qusc
相关产品推荐
相关产品推荐

