Go 同时使用动态和静态绑定(bind)。据我了解,如果您需要使用类型断言,那么它是动态的。我想验证我的假设。
type Xer interface {
X()
}
type XYer interface {
Xer
Y()
}
type Foo struct{}
func (Foo) X() { println("Foo#X()") }
func (Foo) Y() { println("Foo#Y()") }
假设:
foo := Foo{}
// static: Foo -> XYer
var xy XYer = foo
// static: XYer -> Xer
var x Xer = xy
// static: Xer -> interface{}
var empty interface{} = x
// dynamic: interface{} -> XYer
xy2 := empty.(XYer)
// dynamic: XYer -> Foo
foo2 := xy2.(Foo)
因此,当从type A
-> interface B
转换时,如果A
满足B
那么你不不需要断言,可以在编译时生成 itable。如果在不需要断言的地方使用断言,情况会怎样:
var x Xer = Foo{}
empty := x.(interface{})
在这种情况下会发生什么?如果有人可以为我澄清这一点,那就太好了。
最佳答案
为了扩展 jnml 的回答,6g
生成了一个类型断言。
empty := x.(interface{})
扩展为:
0034 (dumb.go:19) MOVQ $type.interface {}+0(SB),(SP)
0035 (dumb.go:19) LEAQ 8(SP),BX
0036 (dumb.go:19) MOVQ x+-32(SP),BP
0037 (dumb.go:19) MOVQ BP,(BX)
0038 (dumb.go:19) MOVQ x+-24(SP),BP
0039 (dumb.go:19) MOVQ BP,8(BX)
0040 (dumb.go:19) CALL ,runtime.assertI2E+0(SB)
0041 (dumb.go:19) MOVQ 24(SP),BX
0042 (dumb.go:19) MOVQ BX,empty+-16(SP)
0043 (dumb.go:19) MOVQ 32(SP),BX
0044 (dumb.go:19) MOVQ BX,empty+-8(SP)
为了弄清楚这里发生了什么,在第 34 行中的 InterfaceType
interface{}
加载到
堆栈的第一个值。第 35-36 行和第 37-38 行放置了 tab and data values x
到堆栈上。然后堆栈准备好 runtime.assertI2E被称为,
它只是将基础类型和数据分配给返回值。编译器知道
您分配给一个空接口(interface),因此调用 assertI2E
:I2E
代表 Eface 的接口(interface)(空接口(interface)),因此无需检查方法。 assertI2E
强制执行的唯一限制是
断言的值必须是一个接口(interface)。
但是,如果您正在执行 x.(Xer)
,runtime.assertI2I
会被调用,然后 checks如果
方法实现接口(interface)。
关于dynamic - 转到接口(interface) : static vs dynamic binding,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15952519/