Swift 不透明类型与协议 - 文档推断协议的功能不能嵌套
Swift Opaque Type vs Protocols - documentation infers protocol's func can't nest
在阅读有关 opaque types 的 Apple Swift 编程语言指南时,有一段我不明白。该指南讨论了不透明类型和协议之间的区别,并指出您不能嵌套调用 return 协议类型。他们使用这个代码片段,其中 Shape 是一个协议:
func protoFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
然后声明:
Another problem with this approach is that the shape transformations don’t nest. The result of flipping a triangle is a value of type Shape, and the protoFlip(:) function takes an argument of some type that conforms to the Shape protocol. However, a value of a protocol type doesn’t conform to that protocol; the value returned by protoFlip(:) doesn’t conform to Shape. This means code like protoFlip(protoFlip(smallTriange)) that applies multiple transformations is invalid because the flipped shape isn’t a valid argument to protoFlip(_:).
然而,我写了这段代码:
import Foundation
protocol P {
associatedtype AT
}
struct C: P {
typealias AT = Int
}
func f<T: P>(_ t: T) -> T {
t
}
func g() {
f(f(C()))
}
g()
这会编译并运行...似乎可以让我嵌套这些调用。
我理解错了什么?文档试图说明什么?
你写了这个:
func f<T: P>(_ t: T) -> T
这需要和 returns 相同的类型。
这不是问题所在。问题是例子:
func protoFlip<T: Shape>(_ shape: T) -> Shape
这需要一个 T 和 returns 一个 Shape 存在。
这相当于:
func f<T: P>(_ t: T) -> P
(存在 T 和 returns P 存在。)
如果您这样写,就会发现您遇到了所描述的问题。您不能将 P existential 传递给 f()
,因为协议 existential 不符合它们在 Swift 中的协议。 (这是由于它可以通过静态方法和初始值设定项创建各种极端情况。今天的协议存在只是不符合他们的协议,而不是处理极端情况。这可能会在未来改变它的情况可以允许,但目前不允许。)
不透明类型允许您编写:
func f<T: P>(_ t: T) -> some P
这个 returns 一个符合 P 的 具体(但不透明)类型,而不是返回 P 存在。系统将其跟踪为“是的类型”由 T 参数化时由 f 返回。”它不等同于任何其他 some P
,但它是具体的,在编译时已知,并且可以传递到 f()
.
在阅读有关 opaque types 的 Apple Swift 编程语言指南时,有一段我不明白。该指南讨论了不透明类型和协议之间的区别,并指出您不能嵌套调用 return 协议类型。他们使用这个代码片段,其中 Shape 是一个协议:
func protoFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
然后声明:
Another problem with this approach is that the shape transformations don’t nest. The result of flipping a triangle is a value of type Shape, and the protoFlip(:) function takes an argument of some type that conforms to the Shape protocol. However, a value of a protocol type doesn’t conform to that protocol; the value returned by protoFlip(:) doesn’t conform to Shape. This means code like protoFlip(protoFlip(smallTriange)) that applies multiple transformations is invalid because the flipped shape isn’t a valid argument to protoFlip(_:).
然而,我写了这段代码:
import Foundation
protocol P {
associatedtype AT
}
struct C: P {
typealias AT = Int
}
func f<T: P>(_ t: T) -> T {
t
}
func g() {
f(f(C()))
}
g()
这会编译并运行...似乎可以让我嵌套这些调用。
我理解错了什么?文档试图说明什么?
你写了这个:
func f<T: P>(_ t: T) -> T
这需要和 returns 相同的类型。
这不是问题所在。问题是例子:
func protoFlip<T: Shape>(_ shape: T) -> Shape
这需要一个 T 和 returns 一个 Shape 存在。
这相当于:
func f<T: P>(_ t: T) -> P
(存在 T 和 returns P 存在。)
如果您这样写,就会发现您遇到了所描述的问题。您不能将 P existential 传递给 f()
,因为协议 existential 不符合它们在 Swift 中的协议。 (这是由于它可以通过静态方法和初始值设定项创建各种极端情况。今天的协议存在只是不符合他们的协议,而不是处理极端情况。这可能会在未来改变它的情况可以允许,但目前不允许。)
不透明类型允许您编写:
func f<T: P>(_ t: T) -> some P
这个 returns 一个符合 P 的 具体(但不透明)类型,而不是返回 P 存在。系统将其跟踪为“是的类型”由 T 参数化时由 f 返回。”它不等同于任何其他 some P
,但它是具体的,在编译时已知,并且可以传递到 f()
.