关于@resultBuilder中buildBlock的参数类型和return类型的问题

A question about parameter type and return type of buildBlock in @resultBuilder

根据swift 语言指南,我需要在定义结果生成器时实现buildBlock 方法。指南还说:

” static func buildBlock(_ components: Component...) -> Component

将一组部分结果合并为一个部分结果。结果生成器必须实现此方法。 “

很明显,参数类型和return类型应该是一样的。但是,如果我使用不同的类型,它似乎也没有问题。我在下面写了一些简单的代码:

@resultBuilder
struct DoubleBuilder {
    static func buildBlock(_ components: Int) -> Double {
        3
    }
}

在Xcode编译成功。类型可以不一样吗?好像和官方指导不一致

编辑:

SwiftUI中ViewBuilder中buildBlock方法的参数类型也与return类型不同。 例如:

static func buildBlock(C0, C1) -> TupleView<(C0, C1)>

当他们说

static func buildBlock(_ components: Component...) -> Component

他们并不严格地表示存在一种类型,ComponentbuildBlock和return必须接受。它们只是意味着 buildBlock 应该接受一些参数,其类型是“部分结果”的类型,而 return 一个类型是“部分结果”的类型。将它们都称为 Component 可能有点令人困惑。

我认为 Swift evolution proposal 解释得更好一些(强调我的):

The typing here is subtle, as it often is in macro-like features. In the following descriptions, Expression stands for any type that is acceptable for an expression-statement to have (that is, a raw partial result), Component stands for any type that is acceptable for a partial or combined result to have, and FinalResult stands for any type that is acceptable to be ultimately returned by the transformed function.

因此 ComponentExpressionFinalResult 等不必固定为单一类型。您甚至可以重载 buildXXX 方法,如稍后在演化提案中所示。

最终,当您实际 使用 结果生成器时,结果生成器会经历对 buildXXX 调用的转换。届时将报告类型错误(如果有)。

例如,

@resultBuilder
struct MyBuilder {
    static func buildBlock(_ p1: String, _ p2: String) -> Int {
        1
    }
}

func foo(@MyBuilder _ block: () -> Double) -> Double {
    block()
}

foo { // Cannot convert value of type 'Int' to closure result type 'Double'
    10 // Cannot convert value of type 'Int' to expected argument type 'String'
    20 // Cannot convert value of type 'Int' to expected argument type 'String'
}

第一个错误是因为结果生成器的结果类型是 Int,但是 foo 的闭包参数需要 return 类型的值 Double。最后两个是因为结果构建器的转换试图调用 MyBuilder.buildBlock(10, 20).

如果您查看转换后的闭包,一切都有意义:

foo {
    let v1 = 10
    let v2 = 20
    return MyBuilder.buildBlock(v1, v2)
}

本质上只要转换后的代码通过编译就没有问题

参见 more details about the transformation here