ResultBuilder 学习笔记(一)

ResultBuilder 学习笔记(一)

ResultBuilder 是Swift 语言的一个非常重要、强大特性,允许开发者以声明方式实现简洁、清晰、优雅的代码。在 Swift 5.4 之前,它被称为@functionBuilder,之后被正式更名为@resultBuilder

使用ResultBuilder技术可以在Swift 中非常容易创建领域特定语言( DSL)。DSL 允许开发人员使用更自然且特定于领域的语法来执行特定任务,例如 SwiftUI 中的 UI 组件构建,从而使代码更易于编写、阅读和维护。

估计许多初学者也和作者开初一样,看了上面描述,对ResultBuilder是什么还是一头雾水。别急,下面我们通过一个简单示例来一一说明。 我们的例子很简单,字符串拼接,将个数不定的字符串拼接起来,形成一个新的字符串。我们比较一下,采用和不采用ResultBuilder这两种情形下有什么差别。

先不采用ResultBuilder。如下函数实现了上述拼接功能:

swift 复制代码
func concat(_ components: String...) ->String
{
    return components.joined(separator: " ")
}

代码非常简单。如下是使用该函数:

swift 复制代码
let str = concat("春眠不觉晓","处处闻啼鸟", "夜来风雨声","花落知多少") 
print(str)

上述代码其实没有什么问题。但是,如果采用下面的ResultBuilder方式是不是更好一些呢?

swift 复制代码
let str = concatBulder {
"春眠不觉晓"
"处处闻啼鸟"
"夜来风雨声"
"花落知多少" 
}
print(str)

与前一种方式比较,后一种方式显然更简洁,自然,你也许会说,把第一种方式换成多行书写,不是一样吗?

swift 复制代码
let str = concat (
  "春眠不觉晓",
  "处处闻啼鸟",
  "夜来风雨声",
  "花落知多少"
) 
print(str)

还真的不一样。首先逗号是多余的,不简洁。其次是小括号,将小括号的内容分解到多行不是很好的实践。

将大括号内容写在一行上也不是好的实践。

如果我们考虑给拼接功能增加一个分隔符,会是怎么样的呢?

第一种方式是这样的:

swift 复制代码
let str = concat (
  "-",
  "春眠不觉晓",
  "处处闻啼鸟",
  "夜来风雨声",
  "花落知多少"
) 
print(str)

显然,问题更严重了。分隔符和正常字符串容易混淆,给使用带来困扰。 加一个参数名separator又如何呢,如下:

swift 复制代码
let str = concat (
  separator:"-",
  "春眠不觉晓",
  "处处闻啼鸟",
  "夜来风雨声",
  "花落知多少"
) 
print(str)

这下,分隔符似乎清楚了,但感觉还是怪怪的,总之还是别扭。

而采用ResultBuilder方式是这样的:

swift 复制代码
let str = concatBuilder("-") { 
  "春眠不觉晓"
  "处处闻啼鸟"
  "夜来风雨声"
  "花落知多少"
}
print(str)

可以看到后者的代码仍然保持简洁、清晰,优雅。

通过上面比较可以看到,即便对这样一个简单的问题,如果稍稍扩展一下(需求),无论如何调整,用普通方式都容易产生不太好的代码。解决办法就是ResultBuilder,它的一个最大的优势就是有助于开发者写出简洁、清晰、优雅的代码。

如何实现

ResultBuilder 技术并不是一组协议,而是一组静态方法。 根据应用需求,我们必须实现其中的一个或者多个方法,而且,必须至少有一个buildBlock()方法。

静态方法 简要说明
buildBlock(...) 构建顺序语句块
buildOptional (...) 构建没有 else 的 if 语句
buildEither(first: )和buildEither(second: ) 构建if-else 语句
buildArray (...) 构建循环语句
buildExpression (...) 构建表达式语句
buildFinalResult (...) 将临时内部类型转换为最终外部类型

通常,我们总是在枚举或者结构体中实现相应的方法。对我们的字符串拼接需求,目前我们只需要实现一个buildBlock()方法即可。

如下是实现代码:

swift 复制代码
@resultBuilder
struct ConcatBuilder {
    static func buildBlock(_ components: String...) -> String {
        return components.joined(separator: "")
    }
}

完毕,就这么简单,我们实现了字符串拼接功能的ResultBuilder版本,它和我们常见的ViewBuilder完全类似,当然啰,功能比后者简单许多。 用上述 ConcatBuilder 改造 concat() 函数, 新函数命名为concatBuilder()。如下:

swift 复制代码
func concatBuilder(@ConcatBuilder _ builder: () -> String) -> String {
    return builder()
}

通过前面的对比,我们已经了解,采用ResultBuilder技术的 concatBuilder 已经比concat()函数优越很多,但它仍然非常简单,我们的拼接需求会变化,我们需要更复杂的功能,比如,我们需要支持if-else语句,或者循环功能。如下所示:

swift 复制代码
var include = true 
let str = concatBuilder { 
  "春眠不觉晓"
   
   for i in 1...5
   {
     "处处闻啼鸟"
   }
   if include 
   { 
   "夜来风雨声" 
   }
   else
   {
     "花落知多少"
   }
}

这些都可以通过在ConcatBuilder结构体中实现更多的的buildXXX()方法来实现。在后续博文中,作者会通过更多示例,介绍如何用ResultBuilder实现上述功能。敬请关注。

相关推荐
YungFan13 小时前
iOS26适配指南之UIButton
ios·swift
麦兜*2 天前
【swift】SwiftUI动画卡顿全解:GeometryReader滥用检测与Canvas绘制替代方案
服务器·ios·swiftui·android studio·objective-c·ai编程·swift
Swift社区3 天前
Swift 实战:从数据流到不重叠区间的高效转换
开发语言·ios·swift
HarderCoder6 天前
Swift 结构体属性:let 与 var 的选择艺术
swift
HarderCoder6 天前
使用 Swift 的 defer 管理状态清理(译文)
swift
HarderCoder6 天前
把 GPT 塞进 iPhone:iOS 26 的 Foundation Models 框架全解析
swift
HarderCoder6 天前
用 SwiftUI 打造“会长大”的组件 —— 从一次性 Alert 到可扩展设计系统
swift
东坡肘子6 天前
苹果首次在中国永久关闭了一家 Apple Store | 肘子的 Swift 周报 #097
swiftui·swift·apple
YungFan7 天前
iOS26适配指南之UIVisualEffectView
ios·swift
大熊猫侯佩10 天前
WWDC 25 玻璃态星际联盟:SwiftUI 视图协同“防御协议”
swiftui·swift·wwdc