类型断言适用对象
var i int32Value =100;
if t,ok := i.(int32);ok {
i = 200;
}
类型断言只能用于interface变量。
invalid type assertion: i.(int32) (non-interface type int32Value on left)
未实现相应接口的方法的断言,编译会失败
type int32Interface interface {
Value() int32
}
var i int32Value =100;
var var_a_int int32= 1000;
var var_b_iface int32Interface = i;
if t,ok := var_b_iface.(int32);ok {
i = 200;
}
int32没有实现接口int32Interface的方法Value
go tool compile -S -N -L type_assert.go > type_assert-n.asm
type_assert.go:73:24: impossible type assertion:
int32 does not implement int32Interface (missing Value method)
int32Value实现了接口方法,编译可以正常编译。
type int32Value int32
type int32Interface interface {
Value() int32
}
func (i int32Value) Value() int32 {
return int32(i)
}
var i int32Value =100;
if t,ok := var_b_iface.(int32Value);ok {
i = 200;
fmt.Println(t);
}
类型断言底层实现
eface断言
59 func func3(var_eface interface{}) int32{
60 t := var_eface.(int32Value)
61 t.Value();
...
}
type eface struct {
_type *_type
data unsafe.Pointer
}
- AX存放的是接口变量的地址。即eface对象地址。eface第一个元素是_type。是一个_type指针。
- DX总存放的是目标类型地址。
因此eface断言,比较的是类型的指针。
将eface._type与目标类型直接进行比较。
比较的是两个指针,即同一个类型在内存中只有一份记录。
0x003a 00058 (type_assert.go:60) MOVL $0, ""..autotmp_10+84(SP)
0x0042 00066 (type_assert.go:60) MOVQ "".var_eface+240(SP), AX //AX为eface._type,具体对象类型
0x004a 00074 (type_assert.go:60) PCDATA $2, $1
0x004a 00074 (type_assert.go:60) MOVQ "".var_eface+248(SP), CX
0x0052 00082 (type_assert.go:60) PCDATA $2, $2
0x0052 00082 (type_assert.go:60) LEAQ type."".int32Value(SB), DX //断言的类型,type."".int32Value
0x0059 00089 (type_assert.go:60) CMPQ AX, DX //比较 type."".int32Value 和 "".var_eface+240(SP)
0x005c 00092 (type_assert.go:60) JEQ 99
0x005e 00094 (type_assert.go:60) JMP 542
0x0063 00099 (type_assert.go:60) PCDATA $2, $0
0x0063 00099 (type_assert.go:60) MOVL (CX), AX
0x0065 00101 (type_assert.go:60) MOVL AX, ""..autotmp_10+84(SP)
0x0069 00105 (type_assert.go:60) MOVL AX, "".t+72(SP)
0x006d 00109 (type_assert.go:61) MOVL "".t+72(SP), AX
0x0071 00113 (type_assert.go:61) MOVL AX, "".i+76(SP)
0x0075 00117 (type_assert.go:61) MOVL $0, "".~r0+64(SP)
0x007d 00125 (type_assert.go:61) XCHGL AX, AX
0x007e 00126 (type_assert.go:26) MOVL "".i+76(SP), AX
0x0082 00130 (type_assert.go:61) MOVL AX, ""..autotmp_13+80(SP)
0x0086 00134 (type_assert.go:61) MOVL AX, "".~r0+64(SP)
0x008a 00138 (type_assert.go:61) JMP 140
type."".int32Value
type."".int32Value SRODATA size=80
0x0000 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0010 5e 3c 98 b9 07 04 04 85 00 00 00 00 00 00 00 00 ^<..............
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 01 00 01 00 10 00 00 00 00 00 00 00 ................
0x0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
rel 24+8 t=1 runtime.algarray+64
rel 32+8 t=1 runtime.gcbits.+0
rel 40+4 t=5 type..namedata.*main.int32Value-+0
rel 44+4 t=5 type.*"".int32Value+0
rel 48+4 t=5 type..importpath."".+0
rel 64+4 t=5 type..namedata.Value.+0
rel 68+4 t=24 type.func() int32+0
rel 72+4 t=24 "".(*int32Value).Value+0
rel 76+4 t=24 "".int32Value.Value+0
iface断言
70 var i int32Value =100;
71
72 var var_a_int int32= 1000;
73 var var_b_iface int32Interface = i;
74 var_a_int = 200;
75 t := var_b_iface.(int32Value);
直接比较iface.tab与目标类型.
- 再看AX中实际的内容. iface.tab是一个itab类型指针。
type iface struct {
tab *itab
data unsafe.Pointer
}
- itab结构
itab的第一个元素inter是一个interafcetype类型指针.
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
- interfacetype结构
interfacetype第一个元素为typ,是一个_type类型。即所有类型的底层结构。
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
由上可以看出:
- AX中存放的就是iface.tab.inter这个指针,指向接口变量中实际存储的动态类型。
- DX中存放的就是目标类型的地址。
- 断言比较的就是两个类型的指针。
0x007a 00122 (type_assert.go:75) MOVL $0, ""..autotmp_19+84(SP)
0x0082 00130 (type_assert.go:75) MOVQ "".var_b_iface+288(SP), AX //接口变量地址放在AX,即AX中即iface.tab
0x008a 00138 (type_assert.go:75) PCDATA $2, $3
0x008a 00138 (type_assert.go:75) MOVQ "".var_b_iface+296(SP), CX
0x0092 00146 (type_assert.go:75) PCDATA $2, $4
0x0092 00146 (type_assert.go:75) LEAQ go.itab."".int32Value,"".int32Interface(SB), DX //将目标类型地址放在 DX
0x0099 00153 (type_assert.go:75) PCDATA $2, $3
0x0099 00153 (type_assert.go:75) CMPQ AX, DX //直接比较两个地址
0x009c 00156 (type_assert.go:75) JEQ 163
0x009e 00158 (type_assert.go:75) JMP 1607
0x00a3 00163 (type_assert.go:75) PCDATA $2, $0
0x00a3 00163 (type_assert.go:75) MOVL (CX), AX
0x00a5 00165 (type_assert.go:75) MOVL AX, ""..autotmp_19+84(SP)
0x00a9 00169 (type_assert.go:75) MOVL AX, "".t+72(SP)
go.itab."".int32Value,"".int32Interface
go.itab."".int32Value,"".int32Interface SRODATA dupok size=32
0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0010 5e 3c 98 b9 00 00 00 00 00 00 00 00 00 00 00 00 ^<..............
rel 0+8 t=1 type."".int32Interface+0
rel 8+8 t=1 type."".int32Value+0
rel 24+8 t=1 "".(*int32Value).Value+0
断言返回值
59 func func3(var_eface interface{}) int32{
60 assert_value := var_eface.(int32Value)
61 var tmp int32 = 1000;
62 fmt.Println(assert_value,tmp)
63 return tmp
64 }
x003d 00061 (type_assert.go:60) MOVL $0, ""..autotmp_9+76(SP)
x0045 00069 (type_assert.go:60) MOVQ "".var_eface+288(SP), AX //将接口变量地址放入AX
x004d 00077 (type_assert.go:60) PCDATA $2, $1
x004d 00077 (type_assert.go:60) PCDATA $0, $1
x004d 00077 (type_assert.go:60) MOVQ "".var_eface+296(SP), CX //将接口变量数据地址放入CX
x0055 00085 (type_assert.go:60) PCDATA $2, $2
x0055 00085 (type_assert.go:60) LEAQ type."".int32Value(SB), DX //将目标数据类型地址放入DX
x005c 00092 (type_assert.go:60) CMPQ AX, DX
x005f 00095 (type_assert.go:60) JEQ 102
x0061 00097 (type_assert.go:60) JMP 618
x0066 00102 (type_assert.go:60) PCDATA $2, $0
x0066 00102 (type_assert.go:60) MOVL (CX), AX //将接口变量值放入AX
x0068 00104 (type_assert.go:60) MOVL AX, ""..autotmp_9+76(SP)
x006c 00108 (type_assert.go:60) MOVL AX, "".assert_value+72(SP) //assert_value类型已知是int32Value, 将接口中的值赋值给断言后变量
总结
- go中每个类型在内存中都只有一份定义。
- 断言就是将接口中保存的动态类型与目标类型的指针进行比较。指针指向同一个位置,即类型正确。
- 断言后的变量类型是确定的,即断言会声明一个指定类型变量,并赋值。
网友评论