与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
看作是实现协议的任何类的类型别名。也就是说,我认为aC
是一个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
看作是实现协议的任何类的类型别名。也就是说,我认为aC
是一个C
不是因为D
符合Self
,而是因为D
字面上是Self
。如果不是D
的类型别名,Self
是什么?特别是,如果class C{}
和protocol P{init({ux:C)}
,如果C
和C
是不同的类型,为什么我可以毫无错误地编写struct a:P{init({C}
?