Swift中为何带具体类型参数的泛型无法匹配装箱类型参数的泛型?
问题原因
Swift的泛型类型默认是不变的——也就是说,即便Icing符合Sweetening协议,Tang<Icing>和Tang<any Sweetening>也属于完全独立的类型,不存在兼容关系。这是因为Tang<S>这个泛型结构体没有被声明为协变(协变允许泛型类型参数的子类型关系传递到泛型本身上),而你又无法修改标准库中的Tang类型来添加协变特性。
本质上,any Sweetening是一个装箱后的存在类型,它和具体的Icing类型处于不同的类型层次,泛型Tang不会自动将Tang<具体类型>隐式转换为Tang<装箱协议类型>。
解决方案
有两种可行的办法,根据你是否能修改Cake类来选择:
方案一:修改Cake的方法为泛型方法
如果可以修改Cake,把c(tang:Tang<Sweetening>)改成泛型方法,这样就能接受任何符合Sweetening的Tang<S>:
class Cake { func c<S: Sweetening>(tang: Tang<S>) -> String { return String(describing: tang) } }
调用cake.c(tang: a1)时,编译器会自动推导S为Icing,完全符合要求,不需要额外转换。
方案二:手动装箱转换(无法修改Cake时)
如果不能修改Cake的方法签名,就在调用时把Tang<Icing>手动转换成Tang<any Sweetening>——通过创建新的Tang实例,将内部的Icing装箱为any Sweetening:
func f() { let a1 = Tang(s:Icing()) // 手动装箱转换 let wrappedTang = Tang(s: a1.s as any Sweetening) let a2 = cake.c(tang: wrappedTang) }
这样wrappedTang的类型就是Tang<any Sweetening>,可以正常传入c方法。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

