Skip to content

闭包 ​

实现状态: 闭包表达式 / 捕获 / HOF 已实现(三后端 parity,测试 fixtures/parity/closures_capture.sy / fixtures/parity/hof.sy);@escaping / @autoclosure / 闭包简写 $0 部分实现;尾随闭包语法 支持

闭包是 自包含的可调用代码块,可捕获周围变量。SYX 闭包与 Swift 风格一致:{ params in body }。

基础语法 ​

swift
let inc = { x in x + 1 }
print(inc(41))                          // 42

let sum = { (a, b) in a + b }
print(sum(1, 2))                        // 3
形式说明
{ x in x + 1 }单参数;x 为参数名
{ (a, b) in a + b }多参数
{ print("hi") }无参数;可省 () in
{ x, y in … }无类型标注(推断)
{ (x: Int) -> Int in x + 1 }显式类型

类型标注 ​

闭包作为变量 / 参数 / 返回值时,可显式标注类型:

swift
let f: (Int) -> Int = { x in x * 2 }
let g: (Int, Int) -> Int = { (a, b) in a + b }
let h: () -> Void = { print("hi") }

类型推断: 作为参数传入时,参数类型由函数签名推断;如推断失败,标注函数签名。

高阶函数(HOF) ​

闭包最常用于 HOF(map / filter / reduce):

swift
let nums = [1, 2, 3, 4, 5]

let doubled = nums.map({ x in x * 2 })               // [2, 4, 6, 8, 10]
let evens   = nums.filter({ x in x % 2 == 0 })       // [2, 4]
let sum     = nums.reduce(0, { acc, x in acc + x })  // 15
let flat    = nums.flatMap({ x in [x, -x] })         // [1, -1, 2, -2, ...]

HOF 走 __syx_array_map / __syx_array_filter / __syx_array_reduce Host 函数(第 32 章 运算符 vs Core Host);闭包参数对应 Array<Element> 的元素。

三后端 parity: map/filter/reduce 在 VM / 统一 MIR / WASM 行为一致(测试 fixtures/parity/hof.sy)。

尾随闭包 ​

参数列表中的最后一个闭包可移到 () 之外:

swift,fragment
let nums = [1, 2, 3, 4, 5]
let evens = nums.filter { x in x % 2 == 0 }           // 等价 nums.filter({ x in x % 2 == 0 })
let dbl   = nums.map { x in x * 2 }                   // 尾随

如果闭包是唯一参数,() 也可省:

swift,fragment
let nums = [1, 2, 3, 4, 5]
let dbl = nums.map { x in x * 2 }                     // 尾随

多闭包: 多个闭包参数时,只有最后一个可尾随;其它仍写 () 内:

swift
arr.reduce(0, combine: { acc, x in acc + x })
//                           ^ 仍带 label

捕获 ​

闭包可捕获外层 let / var:

swift
func makeCounter() -> () -> Int {
    var n = 0
    return { n = n + 1; n }
}

let c = makeCounter()
print(c())         // 1
print(c())         // 2
print(c())         // 3
捕获行为
let 捕获按值捕获(闭包内只读)
var 捕获按引用捕获(闭包可修改)
跨函数返回闭包持有捕获对象(避免过早释放)
swift
let name = "SYX"
let greet = { print("Hello, \(name)") }
greet()                        // "Hello, SYX"

生命周期: 闭包持有捕获对象到自身被释放。多次调用同一闭包修改捕获 var 会影响后续调用(与 Swift 一致)。

闭包作为参数 ​

swift
func twice(f: () -> Int) -> Int {
    return f() + f()
}

let r = twice(f: { 21 })
print(r)                                    // 42

闭包作为返回值 ​

swift
func makeAdder(n: Int) -> (Int) -> Int {
    return { x in x + n }
}

let add5 = makeAdder(n: 5)
print(add5(3))                              // 8

闭包与异步 ​

swift
Task {
    print("in task")
}

Task.detached {
    print("detached")
}

Task { … } 与 Task.detached { … } 接受闭包;详见 第 18 章 并发。

闭包与 Channel ​

swift
class Channel {
    func send(_ handler: (Int) -> Void) {
        handler(0)                          // 演示:调用接收风格闭包
    }
}

func main() {
    let ch = Channel()
    ch.send { v in print("got: \(v)") }
}

详见 第 18 章 并发。

@resultBuilder 中的闭包 ​

swift
@resultBuilder
struct ArrayBuilder {
    static func buildBlock(_ a: Int, _ b: Int, _ c: Int) -> Array<Int> {
        return [a, b, c]
    }
}

@ArrayBuilder
func makeList() -> Array<Int> {
    1
    2
    3
}

func main() {
    let arr = makeList()                    // [1, 2, 3]
    print(arr)
}

详见 第 19 章 宏。

闭包简写 $0 / $1 ​

swift,fragment
let nums = [1, 2, 3, 4, 5]
let doubled = nums.map { $0 * 2 }          // 等价 { x in x * 2 }
let sum     = nums.reduce(0) { $0 + $1 }   // acc + element
简写含义
$0第 0 个参数
$1第 1 个参数
$N第 N 个参数

状态: 部分实现。推荐用 { x in … } 显式写法以保可读性。

闭包作为存储 ​

swift
class Handler {
    var callback: (Int) -> Void = { _ in }
}

let h = Handler()
h.callback = { x in print("got \(x)") }
h.callback(42)                              // "got 42"

闭包存到 class 属性时持有 self 引用;注意避免循环引用(未来 计划支持 [weak self] 捕获列表)。

闭包与生命周期 ​

swift
func callLater(f: () -> String) {
    let s = f()
    print(s)
}

callLater(f: { return "later" })

闭包可作为参数跨函数传递;捕获的对象在闭包被释放前不会被回收。

性能 ​

  • 闭包是 heap 分配的 Closure 对象(与 Swift 类似)
  • 简单闭包可被内联(makeAdder 等单次调用场景,Phase 30+ 内联)
  • 循环内的闭包分配是已知热点;可用 arr.forEach 替代 for-in 闭包

完整示例 ​

swift
func makeCounter(start: Int) -> () -> Int {
    var n = start
    return { n = n + 1; n }
}

func main() {
    // HOF
    let nums = [1, 2, 3, 4, 5]
    let stats = (
        sum: nums.reduce(0) { $0 + $1 },                    // 15
        avg: nums.reduce(0) { $0 + $1 } / nums.count,      // 3
        max: nums.reduce(Int.min) { $0 > $1 ? $0 : $1 }      // 5
    )
    print("sum=\(stats.sum) avg=\(stats.avg) max=\(stats.max)")

    // 捕获
    let c = makeCounter(start: 10)
    print(c())      // 11
    print(c())      // 12

    // 尾随
    let evenSum = nums.filter { $0 % 2 == 0 }.reduce(0) { $0 + $1 }
    print(evenSum)  // 6
}

诊断 ​

代码触发修复
S004闭包参数/返回类型不匹配修正类型标注
S010闭包传给不满足协议约束的 HOF检查协议一致性
P001闭包语法错误检查 { params in body } 结构

与 Swift 的差异 ​

SwiftSYX
$0 / $1 闭包简写部分实现
尾随闭包支持
@escaping未实现(闭包默认 escaping)
@autoclosure未实现
捕获列表 [weak self] / [unowned self]未实现(规划中)
多尾随闭包 arr.sorted(by:) { $0 < $1 }合法
() 单参数可省合法

下一章 → 枚举

参见 → 语言参考:表达式 · 第 7 章 函数 · 第 24 章 泛型 · 第 19 章 宏

SYX · Apache-2.0