为什么使用 Self as return 类型不被视为协议的约束?
Why using Self as return type is not considered as the protocol's constraint?
这是 Swift 中的有效协议声明:
protocol Proto1: class {
func method1() -> Self
func method2() -> [Proto1]
}
但这不是:
protocol Proto2: class {
func method1(param: Self)
func method2() -> [Proto2]
}
错误信息是:
Protocol 'Proto2' can only be used as a generic constraint because it
has Self or associated type requirements
所以看起来,当使用 Self
作为函数的 return 类型时,Swift 没有将其视为正在定义的协议的约束,因此可以使用协议本身作为函数的 return 类型。但是当使用 Self
作为函数的参数类型时,行为就完全不同了。
我想知道为什么会有这样的差异?
因为将 Self
作为方法的参数类型没有用。假设你可以做:
protocol P {
func f(_ x: Self)
}
class A: P {
func f(_ x: Self) {
// not relevant
}
}
class B: A { }
现在假设我有:
func g(x: A) {
// what can I do with x?
}
事实是,没有办法调用x.f
。因为我可以将 B
的实例传递给 x
,在这种情况下 x.f
将接受 B
。 x
可能是我在编译时无法知道的 A
的任何子类的实例,所以我不知道我可以传递什么给 x.f
.
将其与用作 return 类型的 Self
进行比较:
protocol P {
func f() -> Self
}
// Implementation:
class A: P {
func f() -> Self {
self
}
}
class B: A { }
func g(x: A) {
let foo: A = x.f()
}
在这里,我们知道我可以至少 将x.f
的return 值分配给A
类型的变量。即使 x
是 B
的实例,这意味着 f
return 是一个 B
,我们仍然可以将其分配给 [=20] 类型的变量=].
这是 Swift 中的有效协议声明:
protocol Proto1: class {
func method1() -> Self
func method2() -> [Proto1]
}
但这不是:
protocol Proto2: class {
func method1(param: Self)
func method2() -> [Proto2]
}
错误信息是:
Protocol 'Proto2' can only be used as a generic constraint because it has Self or associated type requirements
所以看起来,当使用 Self
作为函数的 return 类型时,Swift 没有将其视为正在定义的协议的约束,因此可以使用协议本身作为函数的 return 类型。但是当使用 Self
作为函数的参数类型时,行为就完全不同了。
我想知道为什么会有这样的差异?
因为将 Self
作为方法的参数类型没有用。假设你可以做:
protocol P {
func f(_ x: Self)
}
class A: P {
func f(_ x: Self) {
// not relevant
}
}
class B: A { }
现在假设我有:
func g(x: A) {
// what can I do with x?
}
事实是,没有办法调用x.f
。因为我可以将 B
的实例传递给 x
,在这种情况下 x.f
将接受 B
。 x
可能是我在编译时无法知道的 A
的任何子类的实例,所以我不知道我可以传递什么给 x.f
.
将其与用作 return 类型的 Self
进行比较:
protocol P {
func f() -> Self
}
// Implementation:
class A: P {
func f() -> Self {
self
}
}
class B: A { }
func g(x: A) {
let foo: A = x.f()
}
在这里,我们知道我可以至少 将x.f
的return 值分配给A
类型的变量。即使 x
是 B
的实例,这意味着 f
return 是一个 B
,我们仍然可以将其分配给 [=20] 类型的变量=].