1-类型断言

类型断言适用对象

        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. 断言后的变量类型是确定的,即断言会声明一个指定类型变量,并赋值。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 1. 值接收者和指针接收者 实现了接收者是值类型的方法, 自动生成 了接收者是指针类型的方法; 实现了接收者是指针...
    浩玥当空阅读 2,351评论 0 10
  • [TOC] 本文基于golang 1.11源码进行分析。先演示用法和注意事项,再深入源码分析原理。 在golang...
    123archu阅读 6,650评论 5 7
  • 1. SAML断言 断言是一个包含零个或更多个由SAML权威做出的声明的信息包。 SAML断言通常与由 元素表示的...
    WebSSO阅读 1,406评论 0 1
  • Golang界面全面介绍 界面介绍 如果说够程和信道是转到并发的两大基石,那么接口是转到语言编程中数据类型的关键。...
    陈卧虫阅读 549评论 0 0
  • [TOC] Golang interface 全面介绍 interface 介绍 如果说goroutine和cha...
    AllenWu阅读 26,586评论 1 20