Swift - 闭包捕获值原理分析

先说原理本质:
编译器在堆上开辟空间,存放了捕获的值

看代码和打印:

func makeIncriementer() -> () -> Int {
    var runnintTotal = 10
    
    func incriementer() -> Int {
        runnintTotal += 1
        return runnintTotal
    }
    return incriementer
}

let makeInc = makeIncriementer()

print(makeInc())
print(makeInc())
print(makeInc())

打印输出:

11
12
13

将代码编译成SIL源码查看
附: 编译指令:swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil

// makeIncriementer()
sil hidden @main.makeIncriementer() -> () -> Swift.Int : $@convention(thin) () -> @owned @callee_guaranteed () -> Int {
bb0:
  %0 = alloc_box ${ var Int }, var, name "runnintTotal" // users: %8, %7, %6, %1
  %1 = project_box %0 : ${ var Int }, 0           // user: %4
  %2 = integer_literal $Builtin.Int64, 10         // user: %3
  %3 = struct $Int (%2 : $Builtin.Int64)          // user: %4
  store %3 to %1 : $*Int                          // id: %4
  // function_ref incriementer #1 () in makeIncriementer()
  %5 = function_ref @incriementer #1 () -> Swift.Int in main.makeIncriementer() -> () -> Swift.Int : $@convention(thin) (@guaranteed { var Int }) -> Int // user: %7
  strong_retain %0 : ${ var Int }                 // id: %6
  %7 = partial_apply [callee_guaranteed] %5(%0) : $@convention(thin) (@guaranteed { var Int }) -> Int // user: %9
  strong_release %0 : ${ var Int }                // id: %8
  return %7 : $@callee_guaranteed () -> Int       // id: %9
} // end sil function 'main.makeIncriementer() -> () -> Swift.Int'

通过源码可以看到,编译器将runnintTotal这个变量是通过
%0 = alloc_box ${ var Int }, var, name "runnintTotal" // users: %8, %7, %6, %1创建的

关于alloc_box 本质是在堆上开辟内存空间,存储了metadata、refrcount、value

WX20211209-172855@2x.png

参照:
SIL开发文档
SIL开发文档-allocBox
The LLVM Compiler Infrastructure
Swift的高级中间语言:SIL

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容