0Pricing
Swift Academy · 课时

自动闭包

使用 @autoclosure 延迟表达式求值。

自动闭包 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

什么是自动闭包

@autoclosure 会自动将参数表达式包装进闭包,因此它直到函数实际使用它时才会求值。调用方只需写普通表达式,而不是闭包。

不使用自动闭包

通常,延迟求值需要在调用位置显式写出闭包:

func logIf(_ cond: Bool, _ message: () -> String) {
    if cond { print(message()) }
}
logIf(true) { "expensive" }  // caller writes braces

使用自动闭包

@autoclosure 允许调用方传入一个不加包装的表达式:

func logIf(_ cond: Bool, _ message: @autoclosure () -> String) {
    if cond { print(message()) }
}
logIf(true, "expensive")  // no braces, evaluated only if cond

延迟求值证明

只有在调用闭包时,表达式才会运行:

func pick(_ cond: Bool, _ value: @autoclosure () -> Int) -> Int {
    cond ? value() : -1
}
func costly() -> Int { print("computed"); return 42 }
print(pick(false, costly()))  // -1  -- "computed" never prints

标准库的使用场景

&& 和 || 运算符、assert 以及 ?? 都使用自动闭包,因此右侧表达式只会在需要时求值。

像 ?? 一样短路

一个在不需要时跳过备用值的自定义默认值函数:

func orElse<T>(_ value: T?, _ fallback: @autoclosure () -> T) -> T {
    value ?? fallback()
}
func makeDefault() -> Int { print("built"); return 0 }
print(orElse(5, makeDefault()))  // 5  -- "built" never prints

惰性的 assert 风格消息

只在检查失败时构建消息:

func check(_ cond: Bool, _ msg: @autoclosure () -> String) {
    if !cond { print("FAIL: \(msg())") }
}
check(true, "this is never built")
check(false, "boom")  // FAIL: boom

自动闭包与逃逸

将其与 @escaping 组合,可以将延迟表达式存储起来供之后使用:

var thunks: [() -> Int] = []
func defer2(_ expr: @autoclosure @escaping () -> Int) {
    thunks.append(expr)
}
defer2(1 + 1)
print(thunks[0]())  // 2  -- computed on demand

让调用位置更清晰

这种优势纯粹来自语法:调用方写入一个值,而函数获得一个闭包:

func unless(_ cond: Bool, _ value: @autoclosure () -> String) -> String {
    cond ? "skipped" : value()
}
print(unless(false, "shown"))  // "shown"

何时不应使用 NOT

自动闭包隐藏了参数其实是闭包这一事实,可能会让读者感到意外。请谨慎使用 — 只有在延迟求值确实有帮助时才使用,例如避免计算昂贵的默认值。

func first<T>(_ a: T?, _ b: @autoclosure () -> T) -> T { a ?? b() }
print(first(nil, 99))  // 99

自动闭包不接受参数

自动闭包始终采用 () -> T 的形式 — 它包装单个表达式,不能接受参数:

func once(_ make: @autoclosure () -> [Int]) -> Int {
    make().count
}
print(once([1, 2, 3]))  // 3

快速检查

@autoclosure 会对它的参数执行什么操作?

回顾

您已经了解了自动闭包:

  • @autoclosure 会将参数表达式包装进 () -> T 闭包
  • 只有在函数调用该闭包时,表达式才会运行 — 这就是延迟求值
  • 它为 &&、||、?? 和 assert 提供支持
  • 与 @escaping 组合即可进行存储;为了清晰起见,请谨慎使用

课程完成!下一步:Equatable、Hashable、Comparable。

常见问题解答

「自动闭包」课时是免费的吗?

是的 — 「自动闭包」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「自动闭包」这节课中我会学到什么?

使用 @autoclosure 延迟表达式求值。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「自动闭包」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 通过引用捕获值
  2. 逃逸闭包
  3. 捕获列表与弱引用 self
  4. 自动闭包
← 返回 Swift Academy