我的 Swift 代码有问题。它无法被编译,因为 swift 在某些协议(protocol)中看不到关联的类型。我找到了重现该问题的最低限度,以下代码代表了它。
protocol Woman {
associatedtype Husband: Man
where Husband.Wife == Self
}
protocol Man {
associatedtype Wife: Woman
where Wife.Husband == Self
}
protocol CoolWoman: Woman //warning
where Husband: CoolMan {
}
protocol CoolMan: Man
where Wife: CoolWoman {
associatedtype Bike: Harley
where Bike.Owner == Self
}
protocol Harley {
associatedtype Owner: CoolMan
where Owner.Bike == Self
}
编译此代码后,我在行中出现以下警告,并用 \\warning
标记:
Redundant conformance constraint 'Self': 'Woman'
这看起来是错误的,因为删除 : Woman where Husband: CoolMan
会使代码无法编译,因此一致性约束并不是多余的。该警告使代码不清楚,但(呃好吧)这是可以容忍的。但下面的函数不可编译的事实不容忽视。
func partnerBike<She: CoolWoman>() -> She.Husband.Bike? { //error
return nil
}
它提供编译错误:
'Husband' is not a member type of 'She'
但这并不是事实,“丈夫是符合酷女人的她的成员”。对我来说,某些处理似乎删除了在编译之前或编译时从代码中发出警告“冗余一致性约束”的约束。
我是否错过了有关 Swift 语法构造的协议(protocol)的某些内容?
或者这只是编译器的一个错误?
为什么我的代码无法编译?
如何做到可编译?
Xcode 11.3 (11C29)、Swift 5
最佳答案
编译器就在那里,你确实有冗余的一致性,问题是它只有一个地方可以删除重复项,但是正如你所注意到的,这会破坏其他东西。
该问题是由 Woman
/Man
系列协议(protocol)之间的循环引用引起的,因为它们的关联类型受到限制。
Woman.Husband
符合 Man
,Man.Wife
符合 Women
。现在,CoolMan
派生自 Man
,这意味着 CoolMan.Wife
已经是一个 Women
。指定 CoolMan.Wife
是 CoolWoman
,而 CoolWomen
是 Women
会导致 Women
从两个不同的路径满足要求,因此出现冗余编译器警告。
这有点类似于菱形继承(钻石问题),编译器无法选择要遵循的继承路径。
这里的解决方案是找到另一种不围绕这么多循环依赖的设计。与保留循环一样,您需要在某个地方打破引用链,而这个地方取决于您想要通过此设计实现的目标。
关于swift - 具有关联类型的协议(protocol)中的开放递归有多大限制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59620879/