@resultBuilder
Swift 5.1에 등장하였던 비공식의 function builder가 Swift 5.4 에서 공식적으로 추가되었다.
일련의 구성 요소들로부터 결과값을 암시적으로 구축할 수 있도록 한다.
함수의 표현식문에서 부분적인 결과를 수집하고 이를 결과값으로 결합하기 위한 임베디드된 DSL로 사용할 수 있다.
return body([
division([
header1("Chapter 1. Loomings."),
paragraph(["Call me Ishmael. Some years ago"]),
paragraph(["There is now your insular city"])
]),
division([
header1("Chapter 2. The Carpet-Bag."),
paragraph(["I stuffed a shirt or two"])
])
])
쉼표, 괄호, 대괄호 등 많은 구두점이 존재한다.
children을 위해 array literal을 사용하고 있기 때문에 type-checker는 Element가 동일한 타입을 갖도록 요구할 것이다.
가장 큰 문제는 이 계층 구조를 변경하는 것이 어색하다는 것이다.
division((useChapterTitles ? [header1("Chapter 1. Loomings.")] : []) +
[paragraph(["Call me Ishmael. Some years ago"]),
paragraph(["There is now your insular city"])])
var
및 subscript
의 경우 선언은 getter를 정의해야하며 속성은 해당 getter의 속성인 것처럼 처리된다.static
메소드이다.BuilderType.<methodName>(<arguments>)
@resultBuilder
struct ExampleResultBuilder {
/// 변환 된 함수의 개별 명령문 표현식 유형.
/// `buildExpression()`이 제공되지 않은 경우 기본값은 Component이다.
typealias Expression = ...
/// 모든 빌드 메소드를 통해 전달되는 부분 결과의 유형
typealias Component = ...
/// 최종 반환 된 결과의 유형.
/// `buildFinalResult()`가 제공되지 않은 경우 기본값은 Component이다.
typealias FinalResult = ...
/// Required by every result builder to build combined results from
/// statement blocks.
static func buildBlock(_ components: Component...) -> Component { ... }
/// If declared, provides contextual type information for statement
/// expressions to translate them into partial results.
static func buildExpression(_ expression: Expression) -> Component { ... }
/// Enables support for `if` statements that do not have an `else`.
static func buildOptional(_ component: Component?) -> Component { ... }
/// With buildEither(second:), enables support for 'if-else' and 'switch'
/// statements by folding conditional results into a single result.
static func buildEither(first component: Component) -> Component { ... }
/// With buildEither(first:), enables support for 'if-else' and 'switch'
/// statements by folding conditional results into a single result.
static func buildEither(second component: Component) -> Component { ... }
/// Enables support for 'for..in' loops by combining the
/// results of all iterations into a single result.
static func buildArray(_ components: [Component]) -> Component { ... }
/// If declared, this will be called on the partial result of an 'if
/// #available' block to allow the result builder to erase type
/// information.
static func buildLimitedAvailability(_ component: Component) -> Component { ... }
/// If declared, this will be called on the partial result from the outermost
/// block statement to produce the final returned result.
static func buildFinalResult(_ component: Component) -> FinalResult { ... }
}
buildBlock
에 대한 호출이 생성되어 결합된 결과를 형성하며, 모든 부분적인 결과들은 unlabelled arguments로 표시된다.buildExpression
메소드를 선언하는 경우, 변환은 이를 unlabelled arguments수로 expression-statement를 전달한다. ()
를 반환하지만 다른 모든 expression statements와 동일한 방식으로 처리된다.()
를 반환하는 expression을 다루는 것을 buildExpression
을 override하여 선택할 수 있다.static func buildExpression(_: ()) -> Component { ... }
if / else
그리고 switch
statement는 케이스에 따라 조건부로 값을 생성한다.
if i == 0 {
"0"
}
📦
var vCase0: String?
if i == 0 {
vCase0 = "0"
}
let v0 = BuilderType.buildOptional(vCase0)
if i == 0 {
"0"
} else if i == 1 {
"1"
} else {
generateFibTree(i)
}
📦
let vMerged: PartialResult
if i == 0 {
vMerged = BuilderType.buildEither(first: "0")
} else if i == 1 {
vMerged = BuilderType.buildEither(second:
BuilderType.buildEither(first: "1"))
} else {
vMerged = BuilderType.buildEither(second:
BuilderType.buildEither(second: generateFibTree(i)))
}
return
은 속성을 몇시적으로 제공하는 func
, getter
에만 적용된다.break
, continue
, guard
는 지원되지 않는다.throw
, defer
, do
for .. in
문은 루프의 각 반복을 실행하여, 모든 반복의 부분적 결과를 배열로 수집한다.
buildArray
로 전달된다.