上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
6.3 方法值
和函数一样,方法除直接调用外,还可赋值给变量,或作为参数传递。
依照引用方式不同,分为表达式(expression)和 值(value) 两种。
type N int func (n N) copy() { fmt.Printf("%p, %v\n", &n, n) } func (n *N) ref() { fmt.Printf("%p, %v\n", n, *n) } // ----------------------------- func main() { var n N = 100 // expression var e func(*N)() = (*N).ref e(&n) // value var v func() = n.ref v() } // 0xc000014080, 100 // 0xc000014080, 100
表达式(expr)很好理解,将方法还原为普通函数,显式传递接收参数(receiver)。
而方法值(value)似乎打包了接收参数和方法,导致签名有所不同。
精简代码,看看具体如何实现。
type N int func (n N) copy() { println(n) } func (n *N) ref() { println(*n) } // ----------------------------- func test(f func()) { f() } func main() { var n N = 100 var v func() = n.copy n++ n.copy() // 101 v() // 100 test(v) // 100 }
$ go build -gcflags "-N -l" $ go tool objdump -S -s "main\.main" ./test func main() { var n N = 100 0x4552b4 MOVQ $0x64, 0x8(SP) var v func() = n.copy 0x4552c3 LEAQ 0x10(SP), CX 0x4552cf LEAQ N.copy-fm(SB), DX 0x4552d6 MOVQ DX, 0x10(SP) 0x4552dd MOVQ 0x8(SP), DX 0x0 +-------------+ 0x4552e2 MOVQ DX, 0x18(SP) | | 0x4552e7 MOVQ CX, 0x20(SP) 0x8 +-------------+ | n = 100 | n++ 0x10 +-------------+ 0x4552ec MOVQ 0x8(SP), CX | copy-fm | 0x4552f1 LEAQ 0x1(CX), AX 0x18 +-------------+ 0x4552f5 MOVQ AX, 0x8(SP) | 100 | 0x20 +-------------+ n.copy() // 101 | ptr -> 0x10 | 0x4552fa CALL N.copy(SB) +-------------+ v() // 100 0x4552ff MOVQ 0x20(SP), DX 0x455304 MOVQ 0(DX), CX 0x455307 CALL CX ; copy-fm test(v) // 100 0x455309 MOVQ 0x20(SP), AX 0x45530e CALL test(SB) }
- 方法值:
funcval { method-fm, receiver-copy }
。 - 换成
n.ref
,无非是复制*N
而已。
TEXT main.N.copy-fm(SB) <autogenerated> 0x45535d MOVQ 0x8(DX), AX // receiver 0x455361 MOVQ AX, 0x8(SP) 0x455366 CALL N.copy(SB) TEXT main.test(SB) 0x455277 MOVQ 0(AX), CX // N.copy-fm 0x45527a MOVQ AX, DX // DX 0x45527d CALL CX
对于空指针(nil),注意内存安全。
type N int func (n N) copy() {} func (n *N) ref() {} // ----------------------------- func main() { var p *N p.ref() // value (*N)(nil).ref() // value (*N).ref(nil) // expression // p.copy() // ~~~~~~ invalid memory address or nil pointer dereference // N.copy(*p) }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论