golang闭包中变量获取
闭包的本质是一个语法糖,其本质是获取外部变量在其内部使用。文中case2和case3并未涉及闭包,只是作为对比案例。case4这个案例有点不能理解,汇编看着太吃力了。case4和case5留待后续再研究。
案例1:
package main
// 探究go语言中闭包如何捕获变量
func main() {
i := 10
closureByValue := func() int {
return i
}
closureByValue()
}
我们直接利用go的compile工具看一下汇编的情况。我用的是windows电脑,在命令行终端敲上这个命令:
go tool compile -l -S main.go | findstr "main.go"
0x0000 00000 (E:/Go/src/tool/closure/closure1/main.go:4) TEXT main.main(SB), ABIInternal, $24-0
0x0000 00000 (E:/Go/src/tool/closure/closure1/main.go:4) CMPQ SP, 16(R14)
0x0004 00004 (E:/Go/src/tool/closure/closure1/main.go:4) PCDATA $0, $-2
0x0004 00004 (E:/Go/src/tool/closure/closure1/main.go:4) JLS 55
0x0006 00006 (E:/Go/src/tool/closure/closure1/main.go:4) PCDATA $0, $-1
0x0006 00006 (E:/Go/src/tool/closure/closure1/main.go:4) PUSHQ BP
0x0007 00007 (E:/Go/src/tool/closure/closure1/main.go:4) MOVQ SP, BP
0x000a 00010 (E:/Go/src/tool/closure/closure1/main.go:4) SUBQ $16, SP
0x000e 00014 (E:/Go/src/tool/closure/closure1/main.go:4) FUNCDATA $0, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure1/main.go:4) FUNCDATA $1, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure1/main.go:6) MOVUPS X15, main..autotmp_3(SP)
0x0013 00019 (E:/Go/src/tool/closure/closure1/main.go:6) LEAQ main.main.func1(SB), AX
0x001a 00026 (E:/Go/src/tool/closure/closure1/main.go:6) MOVQ AX, main..autotmp_3(SP)
0x001e 00030 (E:/Go/src/tool/closure/closure1/main.go:6) MOVQ $10, main..autotmp_3+8(SP)
0x0027 00039 (E:/Go/src/tool/closure/closure1/main.go:9) MOVQ main..autotmp_3(SP), AX
0x002b 00043 (E:/Go/src/tool/closure/closure1/main.go:9) LEAQ main..autotmp_3(SP), DX
0x002f 00047 (E:/Go/src/tool/closure/closure1/main.go:9) PCDATA $1, $0
0x002f 00047 (E:/Go/src/tool/closure/closure1/main.go:9) CALL AX
0x0031 00049 (E:/Go/src/tool/closure/closure1/main.go:10) ADDQ $16, SP
0x0035 00053 (E:/Go/src/tool/closure/closure1/main.go:10) POPQ BP
0x0036 00054 (E:/Go/src/tool/closure/closure1/main.go:10) RET
0x0037 00055 (E:/Go/src/tool/closure/closure1/main.go:10) NOP
0x0037 00055 (E:/Go/src/tool/closure/closure1/main.go:4) PCDATA $1, $-1
0x0037 00055 (E:/Go/src/tool/closure/closure1/main.go:4) PCDATA $0, $-2
0x0037 00055 (E:/Go/src/tool/closure/closure1/main.go:4) CALL runtime.morestack_noctxt(SB)
0x003c 00060 (E:/Go/src/tool/closure/closure1/main.go:4) PCDATA $0, $-1
0x003c 00060 (E:/Go/src/tool/closure/closure1/main.go:4) JMP 0
0x0000 00000 (E:/Go/src/tool/closure/closure1/main.go:6) TEXT main.main.func1(SB), NOSPLIT|NEEDCTXT|NOFRAME|ABIInternal, $0-0
0x0000 00000 (E:/Go/src/tool/closure/closure1/main.go:6) FUNCDATA $0, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure1/main.go:6) FUNCDATA $1, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure1/main.go:6) MOVQ 8(DX), AX
0x0004 00004 (E:/Go/src/tool/closure/closure1/main.go:7) RET
我们重点关注闭包函数及变量。
函数数据与局部变量的初始化
0x000e 00014 (E:/Go/src/tool/closure/closure1/main.go:4) FUNCDATA $0, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure1/main.go:4) FUNCDATA $1, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure1/main.go:6) MOVUPS X15, main..autotmp_3(SP)
0x0013 00019 (E:/Go/src/tool/closure/closure1/main.go:6) LEAQ main.main.func1(SB), AX
0x001a 00026 (E:/Go/src/tool/closure/closure1/main.go:6) MOVQ AX, main..autotmp_3(SP)
0x001e 00030 (E:/Go/src/tool/closure/closure1/main.go:6) MOVQ $10, main..autotmp_3+8(SP)
FUNCDATA
包含一些垃圾收集器使用的元数据。MOVUPS
将X15
寄存器的内容复制到栈上的局部变量main..autotmp_3
。LEAQ
加载main.main.func1
的地址到AX
寄存器。MOVQ AX, main..autotmp_3(SP)
将AX
的值(即main.main.func1
的地址)存储到栈上。MOVQ $10, main..autotmp_3+8(SP)
将常数10存储到栈上的另一个位置。
调用闭包函数
0x0027 00039 (E:/Go/src/tool/closure/closure1/main.go:9) MOVQ main..autotmp_3(SP), AX
0x002b 00043 (E:/Go/src/tool/closure/closure1/main.go:9) LEAQ main..autotmp_3(SP), DX
0x002f 00047 (E:/Go/src/tool/closure/closure1/main.go:9) PCDATA $1, $0
0x002f 00047 (E:/Go/src/tool/closure/closure1/main.go:9) CALL AX
MOVQ main..autotmp_3(SP), AX
将闭包函数的地址从栈加载到AX
寄存器。LEAQ main..autotmp_3(SP), DX
将闭包数据的地址加载到DX
寄存器。CALL AX
调用AX
寄存器中地址指向的函数,即main.main.func1
。
所以,闭包实际上,是把函数外的变量复制到了函数内,供函数内部使用。
案例2:
package main
import (
"fmt"
"time"
)
func passByValue(value int) {
fmt.Println(value)
}
func main() {
for i := 0; i < 10; i++ {
go passByValue(i)
}
time.Sleep(time.Second * 100)
}
这种情况下输出的结果是符合我们的预期的。因为,虽然起了协程,在这个循环中,每次迭代,i
的值会被传递到 passByValue
中。
案例3:
package main
import (
"fmt"
"time"
)
func passByRef(value *int) int {
fmt.Println(*value)
return *value
}
func main() {
for i := 0; i < 10; i++ {
go passByRef(&i)
}
time.Sleep(time.Second * 100)
}
大家猜一下,这种情况下,这种情况下输出的是什么?
这种情况似乎是可以理解的,所有的 goroutine 都在并发执行,并且它们都共享同一个 i
变量的地址。由于 for
循环在 goroutine 启动后继续执行,并且 i
的值会在每次迭代中增加,最终所有 goroutine 都会打印出 i
的最终值。
因此,输出的结果将是 10
,因为当所有 goroutine 开始执行时,i
的值已经增加到 10
。具体来说,可能会打印出多次 10
,具体数量取决于 goroutine 的调度。我的版本是go1.21.5
这里我的函数名是passByRef,似乎有点让人误解,让人误以为是传引用的传参方式,go里面其实没有这种用法,本质上只是拷贝指针的地址传递到函数内。关于这个问题的探究,我在另一篇文章中《golang函数传参——值传递理解》有写过,有兴趣的可以移步过去看看。
但是在go的在线工具中执行,却是这种结果,有点不能理解啊。 这个是go1.22的版本,执行的结果。难道新版本有什么改动么?这个遗留问题,后续有时间再研究研究。
case4:
package main
import (
"fmt"
"time"
)
func passByVal(value int) int {
fmt.Println(value)
return value
}
func main() {
for i := 0; i < 10; i++ {
go func() {
passByVal(i)
}()
}
time.Sleep(time.Second * 100)
}
先看起其执行结果。
再来思考一下,为什么会是这样的执行结果。
首先,看一下汇编的结果。
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:8) TEXT main.passByVal(SB), NOSPLIT|NOFRAME|ABIInternal, $0-8
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:8) FUNCDATA $0, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:8) FUNCDATA $1, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:8) FUNCDATA $5, main.passByVal.arginfo1(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:8) FUNCDATA $6, main.passByVal.argliveinfo(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:8) PCDATA $3, $1
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:10) RET
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:17) TEXT main.main(SB), ABIInternal, $32-0
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:17) CMPQ SP, 16(R14)
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-2
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:17) JLS 117
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-1
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:17) PUSHQ BP
0x0007 00007 (E:/Go/src/tool/closure/closure3/main.go:17) MOVQ SP, BP
0x000a 00010 (E:/Go/src/tool/closure/closure3/main.go:17) SUBQ $24, SP
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:17) FUNCDATA $0, gclocals?J5F+7Qw7O7ve2QcWC7DpeQ==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:17) FUNCDATA $1, gclocals?CnDyI2HjYXFz19SsOj98tw==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:21) LEAQ type:int(SB), AX
0x0015 00021 (E:/Go/src/tool/closure/closure3/main.go:21) PCDATA $1, $0
0x0015 00021 (E:/Go/src/tool/closure/closure3/main.go:21) CALL runtime.newobject(SB)
0x001a 00026 (E:/Go/src/tool/closure/closure3/main.go:21) MOVQ AX, main.&i+16(SP)
0x001f 00031 (E:/Go/src/tool/closure/closure3/main.go:21) NOP
0x0020 00032 (E:/Go/src/tool/closure/closure3/main.go:21) JMP 51
0x0022 00034 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $0, $-2
0x0022 00034 (E:/Go/src/tool/closure/closure3/main.go:22) MOVQ DX, 8(AX)
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $0, $-1
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $1, $1
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:22) CALL runtime.newproc(SB)
0x002b 00043 (E:/Go/src/tool/closure/closure3/main.go:21) MOVQ main.&i+16(SP), AX
0x0030 00048 (E:/Go/src/tool/closure/closure3/main.go:21) INCQ (AX)
0x0033 00051 (E:/Go/src/tool/closure/closure3/main.go:21) CMPQ (AX), $10
0x0037 00055 (E:/Go/src/tool/closure/closure3/main.go:21) JGE 111
0x0039 00057 (E:/Go/src/tool/closure/closure3/main.go:22) LEAQ type:noalg.struct { F uintptr; X0 *int }(SB), AX
0x0040 00064 (E:/Go/src/tool/closure/closure3/main.go:22) CALL runtime.newobject(SB)
0x0045 00069 (E:/Go/src/tool/closure/closure3/main.go:22) LEAQ main.main.func1(SB), CX
0x004c 00076 (E:/Go/src/tool/closure/closure3/main.go:22) MOVQ CX, (AX)
0x004f 00079 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $0, $-2
0x004f 00079 (E:/Go/src/tool/closure/closure3/main.go:22) CMPL runtime.writeBarrier(SB), $0
0x0056 00086 (E:/Go/src/tool/closure/closure3/main.go:22) JNE 96
0x0058 00088 (E:/Go/src/tool/closure/closure3/main.go:22) MOVQ main.&i+16(SP), DX
0x005d 00093 (E:/Go/src/tool/closure/closure3/main.go:22) JMP 34
0x005f 00095 (E:/Go/src/tool/closure/closure3/main.go:22) NOP
0x0060 00096 (E:/Go/src/tool/closure/closure3/main.go:22) CALL runtime.gcWriteBarrier1(SB)
0x0065 00101 (E:/Go/src/tool/closure/closure3/main.go:22) MOVQ main.&i+16(SP), DX
0x006a 00106 (E:/Go/src/tool/closure/closure3/main.go:22) MOVQ DX, (R11)
0x006d 00109 (E:/Go/src/tool/closure/closure3/main.go:22) JMP 34
0x006f 00111 (E:/Go/src/tool/closure/closure3/main.go:32) PCDATA $0, $-1
0x006f 00111 (E:/Go/src/tool/closure/closure3/main.go:32) PCDATA $1, $-1
0x006f 00111 (E:/Go/src/tool/closure/closure3/main.go:32) ADDQ $24, SP
0x0073 00115 (E:/Go/src/tool/closure/closure3/main.go:32) POPQ BP
0x0074 00116 (E:/Go/src/tool/closure/closure3/main.go:32) RET
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:32) NOP
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $1, $-1
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-2
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:17) CALL runtime.morestack_noctxt(SB)
0x007a 00122 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-1
0x007a 00122 (E:/Go/src/tool/closure/closure3/main.go:17) JMP 0
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:22) TEXT main.main.func1(SB), NEEDCTXT|ABIInternal, $16-0
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:22) CMPQ SP, 16(R14)
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $0, $-2
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:22) JLS 33
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $0, $-1
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:22) PUSHQ BP
0x0007 00007 (E:/Go/src/tool/closure/closure3/main.go:22) MOVQ SP, BP
0x000a 00010 (E:/Go/src/tool/closure/closure3/main.go:22) SUBQ $8, SP
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:22) FUNCDATA $0, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:22) FUNCDATA $1, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:22) MOVQ 8(DX), CX
0x0012 00018 (E:/Go/src/tool/closure/closure3/main.go:23) MOVQ (CX), AX
0x0015 00021 (E:/Go/src/tool/closure/closure3/main.go:23) PCDATA $1, $0
0x0015 00021 (E:/Go/src/tool/closure/closure3/main.go:23) CALL main.passByVal(SB)
0x001a 00026 (E:/Go/src/tool/closure/closure3/main.go:24) ADDQ $8, SP
0x001e 00030 (E:/Go/src/tool/closure/closure3/main.go:24) POPQ BP
0x001f 00031 (E:/Go/src/tool/closure/closure3/main.go:24) NOP
0x0020 00032 (E:/Go/src/tool/closure/closure3/main.go:24) RET
0x0021 00033 (E:/Go/src/tool/closure/closure3/main.go:24) NOP
0x0021 00033 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $1, $-1
0x0021 00033 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $0, $-2
0x0021 00033 (E:/Go/src/tool/closure/closure3/main.go:22) CALL runtime.morestack(SB)
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:22) PCDATA $0, $-1
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:22) JMP 0
case5:
package main
import (
"fmt"
"time"
)
func passByRef(value *int) int {
fmt.Println(*value)
return *value
}
func main() {
for i := 0; i < 10; i++ {
go func() {
passByRef(&i)
}()
}
time.Sleep(time.Second * 100)
}
同样的先看一下其执行结果:
再结合其汇编代码看一下为什么会是这样的结果。
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:12) TEXT main.passByRef(SB), NOSPLIT|NOFRAME|ABIInternal, $0-8
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:12) FUNCDATA $0, gclocals?wgcWObbY2HYnK2SU/U22lA==(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:12) FUNCDATA $1, gclocals?J5F+7Qw7O7ve2QcWC7DpeQ==(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:12) FUNCDATA $5, main.passByRef.arginfo1(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:12) FUNCDATA $6, main.passByRef.argliveinfo(SB)
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:12) PCDATA $3, $1
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:14) MOVQ (AX), AX
0x0003 00003 (E:/Go/src/tool/closure/closure3/main.go:14) RET
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:17) TEXT main.main(SB), ABIInternal, $32-0
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:17) CMPQ SP, 16(R14)
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-2
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:17) JLS 117
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-1
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:17) PUSHQ BP
0x0007 00007 (E:/Go/src/tool/closure/closure3/main.go:17) MOVQ SP, BP
0x000a 00010 (E:/Go/src/tool/closure/closure3/main.go:17) SUBQ $24, SP
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:17) FUNCDATA $0, gclocals?J5F+7Qw7O7ve2QcWC7DpeQ==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:17) FUNCDATA $1, gclocals?CnDyI2HjYXFz19SsOj98tw==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:26) LEAQ type:int(SB), AX
0x0015 00021 (E:/Go/src/tool/closure/closure3/main.go:26) PCDATA $1, $0
0x0015 00021 (E:/Go/src/tool/closure/closure3/main.go:26) CALL runtime.newobject(SB)
0x001a 00026 (E:/Go/src/tool/closure/closure3/main.go:26) MOVQ AX, main.&i+16(SP)
0x001f 00031 (E:/Go/src/tool/closure/closure3/main.go:26) NOP
0x0020 00032 (E:/Go/src/tool/closure/closure3/main.go:26) JMP 51
0x0022 00034 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $0, $-2
0x0022 00034 (E:/Go/src/tool/closure/closure3/main.go:27) MOVQ DX, 8(AX)
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $0, $-1
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $1, $1
0x0026 00038 (E:/Go/src/tool/closure/closure3/main.go:27) CALL runtime.newproc(SB)
0x002b 00043 (E:/Go/src/tool/closure/closure3/main.go:26) MOVQ main.&i+16(SP), AX
0x0030 00048 (E:/Go/src/tool/closure/closure3/main.go:26) INCQ (AX)
0x0033 00051 (E:/Go/src/tool/closure/closure3/main.go:26) CMPQ (AX), $10
0x0037 00055 (E:/Go/src/tool/closure/closure3/main.go:26) JGE 111
0x0039 00057 (E:/Go/src/tool/closure/closure3/main.go:27) LEAQ type:noalg.struct { F uintptr; X0 *int }(SB), AX
0x0040 00064 (E:/Go/src/tool/closure/closure3/main.go:27) CALL runtime.newobject(SB)
0x0045 00069 (E:/Go/src/tool/closure/closure3/main.go:27) LEAQ main.main.func1(SB), CX
0x004c 00076 (E:/Go/src/tool/closure/closure3/main.go:27) MOVQ CX, (AX)
0x004f 00079 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $0, $-2
0x004f 00079 (E:/Go/src/tool/closure/closure3/main.go:27) CMPL runtime.writeBarrier(SB), $0
0x0056 00086 (E:/Go/src/tool/closure/closure3/main.go:27) JNE 96
0x0058 00088 (E:/Go/src/tool/closure/closure3/main.go:27) MOVQ main.&i+16(SP), DX
0x005d 00093 (E:/Go/src/tool/closure/closure3/main.go:27) JMP 34
0x005f 00095 (E:/Go/src/tool/closure/closure3/main.go:27) NOP
0x0060 00096 (E:/Go/src/tool/closure/closure3/main.go:27) CALL runtime.gcWriteBarrier1(SB)
0x0065 00101 (E:/Go/src/tool/closure/closure3/main.go:27) MOVQ main.&i+16(SP), DX
0x006a 00106 (E:/Go/src/tool/closure/closure3/main.go:27) MOVQ DX, (R11)
0x006d 00109 (E:/Go/src/tool/closure/closure3/main.go:27) JMP 34
0x006f 00111 (E:/Go/src/tool/closure/closure3/main.go:32) PCDATA $0, $-1
0x006f 00111 (E:/Go/src/tool/closure/closure3/main.go:32) PCDATA $1, $-1
0x006f 00111 (E:/Go/src/tool/closure/closure3/main.go:32) ADDQ $24, SP
0x0073 00115 (E:/Go/src/tool/closure/closure3/main.go:32) POPQ BP
0x0074 00116 (E:/Go/src/tool/closure/closure3/main.go:32) RET
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:32) NOP
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $1, $-1
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-2
0x0075 00117 (E:/Go/src/tool/closure/closure3/main.go:17) CALL runtime.morestack_noctxt(SB)
0x007a 00122 (E:/Go/src/tool/closure/closure3/main.go:17) PCDATA $0, $-1
0x007a 00122 (E:/Go/src/tool/closure/closure3/main.go:17) JMP 0
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:27) TEXT main.main.func1(SB), NEEDCTXT|ABIInternal, $16-0
0x0000 00000 (E:/Go/src/tool/closure/closure3/main.go:27) CMPQ SP, 16(R14)
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $0, $-2
0x0004 00004 (E:/Go/src/tool/closure/closure3/main.go:27) JLS 29
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $0, $-1
0x0006 00006 (E:/Go/src/tool/closure/closure3/main.go:27) PUSHQ BP
0x0007 00007 (E:/Go/src/tool/closure/closure3/main.go:27) MOVQ SP, BP
0x000a 00010 (E:/Go/src/tool/closure/closure3/main.go:27) SUBQ $8, SP
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:27) FUNCDATA $0, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:27) FUNCDATA $1, gclocals?g2BeySu+wFnoycgXfElmcg==(SB)
0x000e 00014 (E:/Go/src/tool/closure/closure3/main.go:27) MOVQ 8(DX), AX
0x0012 00018 (E:/Go/src/tool/closure/closure3/main.go:28) PCDATA $1, $0
0x0012 00018 (E:/Go/src/tool/closure/closure3/main.go:28) CALL main.passByRef(SB)
0x0017 00023 (E:/Go/src/tool/closure/closure3/main.go:29) ADDQ $8, SP
0x001b 00027 (E:/Go/src/tool/closure/closure3/main.go:29) POPQ BP
0x001c 00028 (E:/Go/src/tool/closure/closure3/main.go:29) RET
0x001d 00029 (E:/Go/src/tool/closure/closure3/main.go:29) NOP
0x001d 00029 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $1, $-1
0x001d 00029 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $0, $-2
0x001d 00029 (E:/Go/src/tool/closure/closure3/main.go:27) NOP
0x0020 00032 (E:/Go/src/tool/closure/closure3/main.go:27) CALL runtime.morestack(SB)
0x0025 00037 (E:/Go/src/tool/closure/closure3/main.go:27) PCDATA $0, $-1
0x0025 00037 (E:/Go/src/tool/closure/closure3/main.go:27) JMP 0