与Swift中的通用类一致的关联类型的问题

与Swift中的通用类一致的关联类型的问题,swift,swift-protocols,associated-types,Swift,Swift Protocols,Associated Types,我想定义一个具有关联类型的协议,该类型必须是特定基类的子类。明确地说,假设我有如下示例 C类{ init(arg:T){} } 类别SC:C{} P方案{ 关联类型A:C func-foo(x:A) } 结构D:P{ 类型别名A=C func-foo(x:A){} } 结构E:P{ 类型别名A=SC func-foo(x:A){} } 我希望这段代码能够正确编译。相反,我得到的错误是类型“D”不符合协议“P”,并且类型“E”不符合协议“P”。Xcode还提供以下消息:可能的预期匹配“D.A”(

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

C类{
init(arg:T){}
}
类别SC:C{}
P方案{
关联类型A:C
func-foo(x:A)
}
结构D:P{
类型别名A=C
func-foo(x:A){}
}
结构E:P{
类型别名A=SC
func-foo(x:A){}
}
我希望这段代码能够正确编译。相反,我得到的错误是
类型“D”不符合协议“P”
,并且
类型“E”不符合协议“P”
。Xcode还提供以下消息:
可能的预期匹配“D.A”(又名“C”)不从“C”继承
可能的预期匹配“E.A”(又名“SC”)不从“C”继承

这些错误对我来说毫无意义。在第一种情况下,
C
应与
C
的类型相同,因此
C
应符合
C==C
。在第二种情况下,
C
应该是
C
,因此
SC
应该符合
C==C
。根据Xcode的消息,情况显然并非如此


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

我认为这与您对关联类型以及泛型的理解无关。泛型不是协变的;参数化类型没有替换原则。换句话说,仅仅因为你可以用
D
代替
Self
,并不意味着你可以用
C
代替
C
。它们是不同的类型(不相关)

这里有一个简单的反例来说明我的意思:

class C<T> {
    init(arg: T) {}
}
class Cat {}
class Kitten : Cat {}
我怀疑这是你认为应该起作用的。没有。出于同样的原因,您认为“
C
应该与
C
类型相同”是错误的

<> >让这与你的实际例子更贴切,考虑这个琐碎的例子。这包括:

class C<T> {
    init(arg: T) {}
}
protocol P {
    associatedtype A: C<Any>
    func foo(_ x: A)
}
struct D: P {
    func foo(_ x: C<Any>) {}
}
C类{
init(arg:T){}
}
P方案{
关联类型A:C
func-foo(x:A)
}
结构D:P{
func-foo(x:C){}
}
但这并没有编译:

class C<T> {
    init(arg: T) {}
}
protocol P {
    associatedtype A: C<Any>
    func foo(_ x: A)
}
struct D: P {
    func foo(_ x: C<String>) {}
}
C类{
init(arg:T){}
}
P方案{
关联类型A:C
func-foo(x:A)
}
结构D:P{
func-foo(x:C){}
}

嗯,字符串是Any,你可能会说,那么为什么这个不编译呢?这是因为这一事实无关紧要;泛型中的参数化类型没有替换原则。

我认为这与您对关联类型以及泛型的理解无关。泛型不是协变的;参数化类型没有替换原则。换句话说,仅仅因为你可以用
D
代替
Self
,并不意味着你可以用
C
代替
C
。它们是不同的类型(不相关)

这里有一个简单的反例来说明我的意思:

class C<T> {
    init(arg: T) {}
}
class Cat {}
class Kitten : Cat {}
我怀疑这是你认为应该起作用的。没有。出于同样的原因,您认为“
C
应该与
C
类型相同”是错误的

<> >让这与你的实际例子更贴切,考虑这个琐碎的例子。这包括:

class C<T> {
    init(arg: T) {}
}
protocol P {
    associatedtype A: C<Any>
    func foo(_ x: A)
}
struct D: P {
    func foo(_ x: C<Any>) {}
}
C类{
init(arg:T){}
}
P方案{
关联类型A:C
func-foo(x:A)
}
结构D:P{
func-foo(x:C){}
}
但这并没有编译:

class C<T> {
    init(arg: T) {}
}
protocol P {
    associatedtype A: C<Any>
    func foo(_ x: A)
}
struct D: P {
    func foo(_ x: C<String>) {}
}
C类{
init(arg:T){}
}
P方案{
关联类型A:C
func-foo(x:A)
}
结构D:P{
func-foo(x:C){}
}

嗯,字符串是Any,你可能会说,那么为什么这个不编译呢?这是因为这一事实无关紧要;泛型中的参数化类型没有替换原则。

当然,我可能对错误所在的位置有错误,在这种情况下,我将删除此项。很难读懂别人的心思!如果我没有把我的手指放在这个问题上,我表示歉意。这个答案非常棒,而且解释性很强,但我仍然感到困惑。我现在明白了为什么泛型不应该是协变的,但我想我会把
Self
看作是实现协议的任何类的类型别名。也就是说,我认为a
C
是一个
C
不是因为
D
符合
Self
,而是因为
D
字面上是
Self
。如果不是
D
的类型别名,
Self
是什么?特别是,如果
class C{}
protocol P{init({ux:C)}
,如果
C
C{/code>是不同的类型,为什么我可以毫无错误地编写
struct a:P{init init({ux:C}
,在这种情况下,我会删除这个。很难读懂别人的心思!如果我没有把我的手指放在这个问题上,我表示歉意。这个答案非常棒,而且解释性很强,但我仍然感到困惑。我现在明白了为什么泛型不应该是协变的,但我想我会把
Self
看作是实现协议的任何类的类型别名。也就是说,我认为a
C
是一个
C
不是因为
D
符合
Self
,而是因为
D
字面上是
Self
。如果不是
D
的类型别名,
Self
是什么?特别是,如果
class C{}
protocol P{init({ux:C)}
,如果
C
C
是不同的类型,为什么我可以毫无错误地编写
struct a:P{init({C}