关联类型符合Swift中泛型类的问题

时间:2019-04-09 23:38:15

标签: swift swift-protocols associated-types

我想定义一个具有关联类型的协议,该协议必须是特定基类的子类。明确地说,假设我有类似以下示例的内容。

class C<T> {
    init(arg: T) {}
}

class SC<T>: C<T> {}

protocol P {
    associatedtype A: C<Self>
    func foo(_ x: A)
}

struct D: P {
    typealias A = C<D>
    func foo(_ x: A) {}
}

struct E: P {
    typealias A = SC<E>
    func foo(_ x: A) {}
}

我希望这段代码能够正确编译。相反,我得到了错误Type 'D' does not conform to protocol 'P'Type 'E' does not conform to protocol 'P'。 Xcode还提供以下消息:Possibly intended match 'D.A' (aka 'C<D>') does not inherit from 'C<Self>'Possibly intended match 'E.A' (aka 'SC<E>') does not inherit from 'C<Self>'

这些错误对我来说没有意义。在第一种情况下,C<D>应该与C<Self>具有相同的类型,因此C<D>应该符合C<D> == C<Self>。在第二种情况下,C<Self>应该是C<E>,因此SC<E>应该符合C<E> == C<Self>。根据Xcode的消息,显然不是这种情况。

这是错误消息的编译器错误/问题,还是在这种情况下我误解了关联类型如何工作?

1 个答案:

答案 0 :(得分:2)

我不认为您对关联类型以及泛型的理解有问题。泛型不是协变的;参数化类型没有替代原则。换句话说,仅仅因为您可以在心理上将D放在Self的位置并不意味着您可以用C<D>代替C<Self>。它们是不同的类型(无关)。

这是一个简单的反例,向您展示我的意思:

class C<T> {
    init(arg: T) {}
}
class Cat {}
class Kitten : Cat {}

现在让我们尝试在预期C<Kitten>的地方使用C<Cat>

var c1 = C(arg:Cat())
var c2 = C(arg:Kitten())
c1 = c2 // error

我怀疑是您认为应该起作用的。没有。出于同样的原因,您认为“ C<D>应该与C<Self>属于同一类型”是错误的。

为使此内容与您的实际示例更加相关,请考虑这种琐碎的情况。编译:

class C<T> {
    init(arg: T) {}
}
protocol P {
    associatedtype A: C<Any>
    func foo(_ x: A)
}
struct D: P {
    func foo(_ x: C<Any>) {}
}

但这无法编译:

class C<T> {
    init(arg: T) {}
}
protocol P {
    associatedtype A: C<Any>
    func foo(_ x: A)
}
struct D: P {
    func foo(_ x: C<String>) {}
}

好吧,您可能会说String是Any,那么为什么不编译呢?因为那个事实是无关紧要的。泛型中的参数化类型没有替代原则。