🧠 1. 什么是 @resultBuilder
@resultBuilder 是 Swift 提供的一种 自定义 DSL(领域特定语言) 支持工具,允许你用类似“代码块”的语法构造复杂的值结构。
其广泛应用于 SwiftUI(如 @ViewBuilder)、字符串构建器、HTML DSL 等场景。
✅ 你可以将它理解为:
“让多个表达式拼接或组合为一个最终值的机制”。
🧱 2. 基本结构
swift
复制编辑
@resultBuilder
struct MyBuilder {
static func buildBlock(_ components: T...) -> T
}
其中 T 是你最终组合出的类型,比如 String、View、数组等。
🧩 3. 常用构建方法(方法签名)
一个完整的 resultBuilder 可以实现以下静态方法,支持各种控制流结构:
| 方法 | 用途 |
|---|---|
buildBlock(_:) | 拼接多个表达式的核心方法(必须) |
buildExpression(_:) | 将单个表达式转为构建器的中间值 |
buildOptional(_:) | 支持 if let、if 条件语句 |
buildEither(first:) / buildEither(second:) | 支持 if-else 的两个分支 |
buildArray(_:) | 支持 for-in 结构 |
buildLimitedAvailability(_:) | 支持 #available 编译条件 |
buildFinalResult(_:) | 可选:对最终返回值进行最后处理(Swift 5.9+) |
🧪 4. 简单例子:拼接字符串
swift
复制编辑
@resultBuilder
struct StringBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined()
}
}
func makeString(@StringBuilder _ content: () -> String) -> String {
content()
}
let result = makeString {
"Hello, "
"world!"
}
// 输出: "Hello, world!"
🪜 5. 进阶支持:if、for、可选等控制流
swift
复制编辑
@resultBuilder
struct StringBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined()
}
static func buildOptional(_ component: String?) -> String {
component ?? ""
}
static func buildEither(first: String) -> String {
first
}
static func buildEither(second: String) -> String {
second
}
static func buildArray(_ components: [String]) -> String {
components.joined(separator: ", ")
}
}
然后:
swift
复制编辑
makeString {
"Hello"
if Bool.random() {
"🌞"
} else {
"🌧️"
}
for item in ["A", "B", "C"] {
item
}
}
🧮 6. 在 SwiftUI 中的应用:@ViewBuilder
swift
复制编辑
struct MyView: View {
var body: some View {
VStack {
Text("Hello")
if Bool.random() {
Text("SwiftUI")
} else {
Text("Rocks!")
}
}
}
}
SwiftUI 中的 VStack 使用了 @ViewBuilder,这使得你能用 if、for 等结构直接组合多个视图,而不是手动拼接。
🧑💻 7. 自定义 @resultBuilder 应用场景示例
| 使用场景 | 描述 |
|---|---|
@ViewBuilder | SwiftUI 视图组合 |
@StringBuilder | 构建字符串 DSL |
@HTMLBuilder | 构建 HTML DSL |
@CommandBuilder | 构建命令行工具链 |
@SQLBuilder | 构建 SQL 语句(如:Swift ORM 框架) |
📌 8. Swift 5.9 中的新功能(可选)
✅ buildFinalResult(_:)
这个方法可以对构建器的结果做“最后一轮包装或转换”处理。适用于 Swift 5.9+。
举例,目标:构建 HTML DSL
swift
复制编辑
let html = makeHTML {
HTML("html") {
HTML("body") {
HTML("h1") { "Welcome" }
HTML("p") { "This is a custom DSL!" }
}
}
}
print(html.render())
🧱 第一步:定义 HTML 节点结构
swift
复制编辑
protocol HTMLComponent {
func render() -> String
}
struct HTMLText: HTMLComponent {
let text: String
func render() -> String {
text
}
}
struct HTML: HTMLComponent {
let tag: String
let children: [HTMLComponent]
init(_ tag: String, @HTMLBuilder _ content: () -> [HTMLComponent]) {
self.tag = tag
self.children = content()
}
func render() -> String {
let inner = children.map { $0.render() }.joined()
return "<(tag)>(inner)</(tag)>"
}
}
🧙 第二步:定义 @HTMLBuilder
swift
复制编辑
@resultBuilder
struct HTMLBuilder {
static func buildBlock(_ components: HTMLComponent...) -> [HTMLComponent] {
components
}
static func buildOptional(_ component: [HTMLComponent]?) -> [HTMLComponent] {
component ?? []
}
static func buildEither(first component: [HTMLComponent]) -> [HTMLComponent] {
component
}
static func buildEither(second component: [HTMLComponent]) -> [HTMLComponent] {
component
}
static func buildArray(_ components: [[HTMLComponent]]) -> [HTMLComponent] {
components.flatMap { $0 }
}
static func buildExpression(_ expression: String) -> [HTMLComponent] {
[HTMLText(text: expression)]
}
static func buildExpression(_ expression: HTMLComponent) -> [HTMLComponent] {
[expression]
}
}
🧪 第三步:封装顶层构造器
swift
复制编辑
func makeHTML(@HTMLBuilder content: () -> [HTMLComponent]) -> HTMLComponent {
let result = content()
return HTMLText(text: result.map { $0.render() }.joined(separator: "\n"))
}
📦 最终效果
swift
复制编辑
let html = makeHTML {
HTML("html") {
HTML("body") {
HTML("h1") { "Hello Swift!" }
HTML("p") {
if Bool.random() {
"Dynamic paragraph!"
} else {
"Static paragraph!"
}
}
}
}
}
print(html.render())
输出可能为:
html
复制编辑
<html><body><h1>Hello Swift!</h1><p>Static paragraph!</p></body></html>
📚 小结
| 特性 | 说明 |
|---|---|
| 灵活组合 | 像 DSL 一样用多个表达式组合出结构 |
| 控制流 | 支持 if/else、for、可选绑定等 |
| 编译期支持 | 编译器会在语法上理解这些结构 |
| SwiftUI | SwiftUI 的构建基石 |
| 可扩展性强 | 适用于构建任意复杂层级的数据 |