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().