0

以下 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 的答案所指)可以在这个问题的编辑历史中找到。

4

1 回答 1

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)。删除: PinU : P会删除错误,尽管这可能不是您想要的。再说一次,根据您的需要,可能有任意数量的解决方案:)

编辑

以下是对@igul222 大大简化的代码示例的回应。但是,我仍然认为,编译器只是返回一个不太有用的错误消息,这实际上是由递归类型定义引起的。例如,如果您enum根据自身定义 an:

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`'

编译器似乎在说的是 Selfin C<Self>is not yet A,即那A还不是它,Self因为A它必须符合Pwhich 依次等待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() }
}

一些函数式编程模式需要递归定义的类型,所以在 Swift 中使用它可能会很好。但是,目前,我不确定是否可以有效地遵循具有 form 关联类型的协议T<Self>,即使编译器允许其定义......否则,这一切都应该在运行时工作。

编辑 2

我刚刚升级到Xcode 6.1 GM Seed,情况发生了变化!以下片段,以前不会编译,现在编译并且运行良好!

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         // --> {{{...}}}

然而,这种改进并没有扩展到递归定义的关联类型。

于 2014-09-29T23:16:23.563 回答