先说原理本质:
编译器在堆上开辟空间,存放了捕获的值
看代码和打印:
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