Swift Result Builders (@resultBuilder)
Result Builder 是 Swift 5.4 引入的強大功能,它允許你將一系列的表達式 (Expressions) 轉換成單一個值。
這就是 SwiftUI 魔法的核心。當你寫 VStack { Text("A"); Text("B") } 時,為什麼這些分開的語句會自動組合成一個畫面?背後就是 Result Builder 在運作。
為什麼需要 Result Builder?
它的目的是為了創建 DSL (Domain Specific Language,領域特定語言)。讓程式碼具有宣告式 (Declarative) 的風格,更容易閱讀和撰寫。
基本範例:字串構造器
讓我們建立一個簡單的 StringBuilder,它可以把多個字串連接起來,中間用換行符號隔開。
1. 定義 Builder
首先,我們宣告一個結構並標記 @resultBuilder。必須實作靜態方法 buildBlock。
@resultBuilder
struct StringBuilder {
// 這是最基本的方法:處理多個子元件
static func buildBlock(_ components: String...) -> String {
return components.joined(separator: "\n")
}
}
2. 使用 Builder
我們可以用 @StringBuilder 來修飾函式參數,這樣該函式就能接受「區塊語法」。
func makeString(@StringBuilder _ content: () -> String) -> String {
return content()
}
// 實際呼叫
let explicitString = makeString {
"Hello"
"World"
"This is Swift"
}
print(explicitString)
/* 輸出:
Hello
World
This is Swift
*/
注意到我們不需要寫 return "Hello",也不需要用陣列 ["Hello", "World"] 包起來。Result Builder 會自動幫我們收集這些字串並傳給 buildBlock。
分支控制 (Conditionals)
如果我們想在 Builder 中使用 if 語句,必須實作 buildOptional 或 buildEither。
extension StringBuilder {
// 處理 if 語句 (沒有 else 的情況)
static func buildOptional(_ component: String?) -> String {
return component ?? ""
}
}
let name = "Mike"
let isFormal = false
let greeting = makeString {
"Hi, \(name)"
if isFormal {
"Nice to meet you."
}
}
// 輸出:
// Hi, Mike
SwiftUI 中的應用 (@ViewBuilder)
SwiftUI 的 View 建立過程就是 Result Builder 的極致應用。VStack、HStack、Group 等容器的初始化器都使用了 @ViewBuilder。
// SwiftUI 的 ViewBuilder 簡化版概念
@resultBuilder
struct ViewBuilder {
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View {
return TupleView((c0, c1))
}
// ... 針對不同數量的參數有不同的 buildBlock 重載
}
這就是為什麼在 SwiftUI 中我們這寫:
VStack {
Text("Title")
if showImage {
Image("logo")
}
}
這比傳統的 UIKit 寫法 (建立 View -> addSubview -> 設定 Layout) 要簡潔直觀得多。
總結
@resultBuilder讓你自定義「區塊語法」的處理邏輯。- 它是 SwiftUI 宣告式語法的基石。
- 你可以利用它來創建自己的 DSL (例如 HTML 生成器、SQL 查詢構造器)。