美文网首页
1-类型断言

1-类型断言

作者: 浩玥当空 | 来源:发表于2019-06-05 22:27 被阅读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. 断言后的变量类型是确定的,即断言会声明一个指定类型变量,并赋值。

    相关文章

      网友评论

          本文标题:1-类型断言

          本文链接:https://www.haomeiwen.com/subject/yadexctx.html