Go 方法接收器的正规化
2022-7-19 09:4:12 Author: Go语言中文网(查看原文) 阅读量:13 收藏

Go 允许一些选择器的简化形式。

例如,在下面这个程序中,t1.M1 是 (*t1).M1 的简化形式,而 t2.M2 则是 (&t2).M2 的简化形式。

在编译时,编译器将把简化的形式正规化为它们原来各自的完整形式。

下面这个程序打印出 0 和 9,因为对 t1.X 的修改对 (*t1).M1 的估值结果没有影响。

package main
type T struct { X int}
func (t T) M1() int { return t.X}
func (t *T) M2() int { return t.X}
func main() { var t1 = new(T) var f1 = t1.M1 // <=> (*t1).M1 t1.X = 9 println(f1()) // 0 var t2 T var f2 = t2.M2 // <=> (&t2).M2 t2.X = 9 println(f2()) // 9}

在下面的代码中,函数 foo 运行正常,但函数 bar 会产生恐慌。

原因是 s.M 是 (*s.T).M 的简化形式。

在编译时,编译器会将此简化形式规范化为原来的完整形式。

在运行时,如果 s.T 是 nil,那么对 *s.T 的估值将导致一个恐慌。

对 s.T 的两次修改对 *s.T 的估值结果没有影响。

package main
type T struct { X int}
func (t T) M() int { return t.X}
type S struct { *T}
func foo() { var s = S{T: new(T)} var f = s.M // <=> (*s.T).M s.T = nil f()}
func bar() { var s S var f = s.M // panic s.T = new(T) f()}
func main() { foo() bar()}

请注意,接口方法值和通过反射得到的方法值将被延迟扩展为提升的方法值。

例如,在下面的程序中,对 s.T.X 的修改对通过反射和接口方式得到的方法值的返回值有影响。

package main
import "reflect"
type T struct { X int}
func (t T) M() int { return t.X}
type S struct { *T}
func main() { var s = S{T: new(T)} var f = s.M // <=> (*s.T).M var g = reflect.ValueOf(&s).Elem(). MethodByName("M"). Interface().(func() int) var h = interface{M() int}(s).M s.T.X = 3 println( f() ) // 0 println( g() ) // 3 println( h() ) // 3}

来源:https://github.com/golang/go/issues/47863

但是,在当前版本(1.18 版本)的官方标准 Go 编译器的实现中存在一个 bug。

官方标准 Go 编译器中一个优化会将一些接口方法值过度去虚拟化(de-virtualization),从而导致不正确的结果。

比如,下面这个程序应该打印出 2 2,但是目前它却打印出 1 2

package main
type I interface{ M() }
type T struct{ x int}
func (t T) M() { println(t.x)}
func main() { var t = &T{x: 1} var i I = t var f = i.M defer f() // 2(正确) // i.M 将在编译时刻被(错误地)去虚拟化为 (*t).M。 defer i.M() // 1(错误) t.x = 2}

目前尚不清楚此 bug 何时将被修复。

来源:https://github.com/golang/go/issues/52072


推荐阅读

福利
我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。


文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMTA4Njc0OQ==&mid=2651453166&idx=1&sn=712dfff5b62406d4893fb441658f3b28&chksm=80bb281cb7cca10abe99edcbc52685be350444c004393486e21616d6ddfd5cb38e5eec951424#rd
如有侵权请联系:admin#unsafe.sh