09-go类型断言

22 篇文章 1 订阅
1 篇文章 0 订阅

类型断言适用对象

        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
}
  1. AX存放的是接口变量的地址。即eface对象地址。eface第一个元素是_type。是一个_type指针。
  2. 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与目标类型.

  1. 再看AX中实际的内容. iface.tab是一个itab类型指针。
type iface struct {
	tab  *itab
	data unsafe.Pointer
}
  1. 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.
}
  1. interfacetype结构
    interfacetype第一个元素为typ,是一个_type类型。即所有类型的底层结构。
type interfacetype struct {
	typ     _type
	pkgpath name
	mhdr    []imethod
}

由上可以看出:

  1. AX中存放的就是iface.tab.inter这个指针,指向接口变量中实际存储的动态类型。
  2. DX中存放的就是目标类型的地址。
  3. 断言比较的就是两个类型的指针。
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, 将接口中的值赋值给断言后变量

总结

  1. go中每个类型在内存中都只有一份定义。
  2. 断言就是将接口中保存的动态类型与目标类型的指针进行比较。指针指向同一个位置,即类型正确。
  3. 断言后的变量类型是确定的,即断言会声明一个指定类型变量,并赋值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值