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