以下Swift代码在最后一行产生此错误:Type 'E' does not inherit from 'C<Self>'
。不确定这里发生了什么。任何线索都会受到赞赏。
class C<T> {}
protocol P {
typealias E : C<Self>
}
class A : P {
typealias E = C<A>
}
class S<U : P> {}
class C2<T> : S<A> {}
更新:我简化了破碎的例子。旧版本(milos&#39;答案所指的)可以在这个问题的编辑历史中找到。
答案 0 :(得分:3)
我已重命名您的标识符,以便我可以考虑一下:
protocol P {
typealias E : C<Self>
}
class A : P {
typealias E = C1<Any>
}
class B : P {
typealias E = C2<Any>
}
class C<T> {}
class C1<T> : C<A> {}
class S<T, U : P> : C<T> {} // <-- mark!
class C2<T> : S<B, A> {}
这应该最终,而且几乎可以解决。实际上,你想要的是:
class B : P {
typealias E = C<B> // which is what P requires (same with class A)
}
但是,在标记的行上,您要定义class S
,您要求编译器检查U : P
的类型,然后将B
作为要检查的具体类型。不幸的是,此时B
与P
的一致性仍未得到解决(即它本身是根据C2 : S : C
定义的,这是U : P
的用途。 。删除: P
中的U : P
会删除错误,但这可能不是您想要的。然后,根据你的需要,可能有任何数量的解决方案:)
修改强>
以下是对@igul222的简化代码示例的回应。但是,我仍然认为,编译器只是返回一个不太有用的错误消息,这实际上是由递归类型定义引起的。例如,考虑一下如果你自己定义一个enum
:
enum E {
case C(E) // error: recursive value type 'E' is not allowed
}
现在,这可能也是以下问题:
class C<T> {}
protocol P {
typealias E : C<Self>
var c: E { get }
}
final class A : P {
typealias E = C<A>
var c: E { return E() }
}
// --> error: type 'A' does not conform to protocol 'P'
// --> note: protocol requires property 'c' with type 'E'
// --> note: candidate has non-matching type 'E'
......这也不起作用(你的要点的一个版本):
class C<T> {}
protocol P {
typealias E : C<Self>
}
final class A : P {
typealias E = C<A>
}
class X<U : P> {}
X<A>() // --> error: type 'E' does not inherit from 'C<`Self`>'
......或者这个:
class C<T> {}
protocol P {
typealias E : C<Self>
}
final class A : P {
typealias E = C<A>
}
let a = A()
func f<T: P>(T) {}
f(a) // --> error: 'A' is not identical to '`Self`'
编译器似乎在说Self
中的C<Self>
还不是A
,即A
还不是Self
是A
它必须符合P
,而C<Self>
正在等待A
签出...但以下工作原因是class C<T> {}
protocol P {
var c: C<Self> { get }
}
final class A : P {
typealias E = C<A> // just a typealias, no longer an associated type
var c: E { return E() }
}
不再根据自身定义关联类型:
T<Self>
某些函数式编程模式需要递归定义的类型,因此在Swift中使用它可能会很好。但是,目前我不确定是否可以有效地遵循具有protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
class Ca: A {
var b: B?
}
class Cb: B {
var a: A?
}
let a = Ca() // --> {nil}
let b = Cb() // --> {nil}
a.b = b // --> {{{...}}}
b.a = a // --> {{{...}}}
形式的关联类型的协议,即使编译器允许其定义...否则,这应该只在运行时工作。 / p>
我刚刚升级到 Xcode 6.1 GM Seed ,情况发生了变化!以前编译过的以下片段现在编译并且看起来运行正常!
{{1}}
但是,这种改进并未扩展到递归定义的关联类型。