Swift中为何无法访问泛型关联类型T.ItemType的id成员
问题原因
核心是你混淆了Swift关联类型的默认值声明和类型约束的语法,二者作用完全不同:
- 你在
ProtoB里写的associatedtype ItemType = ProtoA,其中=是给关联类型设置默认值,不代表对ItemType的类型约束。也就是说,任何实现ProtoB的类型,完全可以把ItemType自定义为Int、String等任意没有id属性的类型,编译器无法保证所有场景下T.ItemType都存在id属性,因此compareId方法直接访问item.id会报错。 compareIdW方法额外添加了泛型约束<U: ProtoA>+ 条件where U == T.ItemType,相当于给当前方法的入参类型强制增加了「必须符合ProtoA协议」的限制,编译器此时可以确认入参一定有id属性,因此可以正常访问。
修复方案
有两种常见的修复思路,根据你的业务需求选择即可:
方案1:给ProtoB的关联类型增加约束(全局生效)
如果你要求所有ProtoB的实现的ItemType都必须符合ProtoA协议,只需要把ProtoB中的关联类型声明修改为带约束的写法:
protocol ProtoB: Identifiable{ // : 代表类型约束,也可以同时保留默认值写成 associatedtype ItemType: ProtoA = ProtoA associatedtype ItemType: ProtoA var id: UUID { get } var arrayOfItems: [ItemType] { get } }
修改后编译器会强制所有ProtoB的ItemType都符合ProtoA协议,自然保证了id属性存在,原有报错的compareId方法即可正常运行。
方案2:给M类增加局部约束(仅对当前类生效)
如果你不想修改全局的ProtoB定义,只需要保证当前M类使用的T.ItemType符合ProtoA,可以直接给M类添加约束:
// 增加where子句约束T.ItemType必须符合ProtoA class M<T:ProtoB> where T.ItemType: ProtoA { // 类内部原有代码不需要修改,compareId方法报错会自动消失 }
内容的提问来源于stack exchange,提问作者Jason Krowl
相关产品推荐
相关产品推荐

