4.refelct.MethodByName()

3. 接口方法实现-MethodByName()方法

  1. 将动态类型压入栈,作为MethodByName。
  2. Type变量176偏移位置为MethodByName()方法地址。

0x01ba 00442 ($GOROOT/src/reflect/type.go:3007) MOVQ    reflect.t+224(SP), AX
0x01c2 00450 ($GOROOT/src/reflect/type.go:3007) MOVQ    AX, ""..autotmp_90+280(SP)
0x01ca 00458 ($GOROOT/src/reflect/type.go:1376) PCDATA  $2, $4
0x01ca 00458 ($GOROOT/src/reflect/type.go:1376) LEAQ    go.itab.*reflect.rtype,reflect.Type(SB), CX
0x01d1 00465 ($GOROOT/src/reflect/type.go:1376) MOVQ    CX, ""..autotmp_97+1384(SP)
0x01d9 00473 ($GOROOT/src/reflect/type.go:1376) MOVQ    AX, ""..autotmp_97+1392(SP)
0x01e1 00481 ($GOROOT/src/reflect/type.go:1376) PCDATA  $2, $1
0x01e1 00481 ($GOROOT/src/reflect/type.go:1376) PCDATA  $0, $7
0x01e1 00481 ($GOROOT/src/reflect/type.go:1376) MOVQ    CX, "".~R0+792(SP)
0x01e9 00489 ($GOROOT/src/reflect/type.go:1376) PCDATA  $2, $0
0x01e9 00489 ($GOROOT/src/reflect/type.go:1376) MOVQ    AX, "".~R0+800(SP)
0x01f1 00497 ($GOROOT/src/reflect/type.go:1376) JMP     499
0x01f3 00499 (reflect.go:23)    PCDATA  $2, $1
0x01f3 00499 (reflect.go:23)    MOVQ    "".~R0+800(SP), AX
0x01fb 00507 (reflect.go:23)    PCDATA  $0, $3
0x01fb 00507 (reflect.go:23)    MOVQ    "".~R0+792(SP), CX
0x0203 00515 (reflect.go:23)    MOVQ    CX, ""..autotmp_98+1368(SP)
0x020b 00523 (reflect.go:23)    MOVQ    AX, ""..autotmp_98+1376(SP)
0x0213 00531 (reflect.go:23)    MOVQ    CX, "".~R0+776(SP)
0x021b 00539 (reflect.go:23)    MOVQ    AX, "".~R0+784(SP)
0x0223 00547 (reflect.go:23)    JMP     549
0x0225 00549 (reflect.go:23)    PCDATA  $0, $8
0x0225 00549 (reflect.go:23)    MOVQ    CX, "".var_type+952(SP)
0x022d 00557 (reflect.go:23)    PCDATA  $2, $0
0x022d 00557 (reflect.go:23)    MOVQ    AX, "".var_type+960(SP)
0x0235 00565 (reflect.go:24)    MOVL    $3000, "".var_int32+116(SP)
0x023d 00573 (reflect.go:25)    PCDATA  $2, $5
0x023d 00573 (reflect.go:25)    LEAQ    ""..autotmp_91+2744(SP), DI
0x0245 00581 (reflect.go:25)    XORPS   X0, X0
0x0248 00584 (reflect.go:25)    PCDATA  $2, $0
0x0248 00584 (reflect.go:25)    LEAQ    -48(DI), DI
0x024c 00588 (reflect.go:25)    DUFFZERO$277

0x025f 00607 (reflect.go:25)    MOVQ    "".var_type+952(SP), AX //Type接口变量 
0x0267 00615 (reflect.go:25)    TESTB   AL, (AX)
0x0269 00617 (reflect.go:25)    MOVQ    176(AX), AX //MethodByName函数偏移量176
0x0270 00624 (reflect.go:25)    PCDATA  $2, $2
0x0270 00624 (reflect.go:25)    MOVQ    "".var_type+960(SP), CX
0x0278 00632 (reflect.go:25)    PCDATA  $2, $0
0x0278 00632 (reflect.go:25)    MOVQ    CX, (SP)
0x027c 00636 (reflect.go:25)    PCDATA  $2, $2
0x027c 00636 (reflect.go:25)    LEAQ    go.string."Test_MethodByName1"(SB), CX
0x0283 00643 (reflect.go:25)    PCDATA  $2, $0
0x0283 00643 (reflect.go:25)    MOVQ    CX, 8(SP)
0x0288 00648 (reflect.go:25)    MOVQ    $18, 16(SP)
0x0291 00657 (reflect.go:25)    CALL    AX  //调用 MethodByName 方法

3.1 MethodByName()方法实现

//src\reflect\type.go

func (t *rtype) MethodByName(name string) (m Method, ok bool) {
    if t.Kind() == Interface {
        tt := (*interfaceType)(unsafe.Pointer(t))
        return tt.MethodByName(name)
    }
    ut := t.uncommon()
    if ut == nil {
        return Method{}, false
    }
    // TODO(mdempsky): Binary search.
    for i, p := range ut.exportedMethods() {
        if t.nameOff(p.name).name() == name {
            return t.Method(i), true
        }
    }
    return Method{}, false
}

3.2 如果动态类型本身就是一个接口

  1. 将变量转换为interfaceType类型。(iface变量第一个元素就是interfaceType类型)
  2. interfaceType.methods保存了接口所有方法。
  3. 根据方法名,找到对应方法。

3.2.1 interfaceType.MethodByName(name string)

  1. methods保存了接口的所有方法。
  2. 遍历methods找到匹配的方法.
// MethodByName method with the given name in the type's method set.
func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
    if t == nil {
        return
    }
    var p *imethod
    for i := range t.methods {
        p = &t.methods[i]
        if t.nameOff(p.name).name() == name {
            return t.Method(i), true
        }
    }
    return
}

3.2.2 interfaceType.nameOff()

  1. 根据interfaceType变量地址,由运行时找到对应的名字。
type nameOff int32 // offset to a name
type typeOff int32 // offset to an *rtype
type textOff int32 // offset from top of text section

type name struct {
    bytes *byte
}

func (t *rtype) nameOff(off nameOff) name {
    return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}
}

// resolveNameOff resolves a name offset from a base pointer.
// The (*rtype).nameOff method is a convenience wrapper for this function.
// Implemented in the runtime package.
func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer

23  var var_type reflect.Type = reflect.TypeOf(var_person)
25  mymethod,b := var_type.MethodByName("Test_MethodByName1")

对应汇编

0x023d 00573 (reflect.go:25)    LEAQ    ""..autotmp_91+2744(SP), DI
0x0245 00581 (reflect.go:25)    XORPS   X0, X0
0x0248 00584 (reflect.go:25)    PCDATA  $2, $0
0x0248 00584 (reflect.go:25)    LEAQ    -48(DI), DI
0x024c 00588 (reflect.go:25)    DUFFZERO    $277
0x025f 00607 (reflect.go:25)    MOVQ    "".var_type+952(SP), AX
0x0267 00615 (reflect.go:25)    TESTB   AL, (AX)
0x0269 00617 (reflect.go:25)    MOVQ    176(AX), AX
0x0270 00624 (reflect.go:25)    PCDATA  $2, $2
0x0270 00624 (reflect.go:25)    MOVQ    "".var_type+960(SP), CX
0x0278 00632 (reflect.go:25)    PCDATA  $2, $0
0x0278 00632 (reflect.go:25)    MOVQ    CX, (SP)
0x027c 00636 (reflect.go:25)    PCDATA  $2, $2
0x027c 00636 (reflect.go:25)    LEAQ    go.string."Test_MethodByName1"(SB), CX
0x0283 00643 (reflect.go:25)    PCDATA  $2, $0
0x0283 00643 (reflect.go:25)    MOVQ    CX, 8(SP)
0x0288 00648 (reflect.go:25)    MOVQ    $18, 16(SP)
0x0291 00657 (reflect.go:25)    CALL    AX
0x0293 00659 (reflect.go:25)    PCDATA  $2, $5
0x0293 00659 (reflect.go:25)    PCDATA  $0, $9
0x0293 00659 (reflect.go:25)    LEAQ    ""..autotmp_91+2744(SP), DI
0x029b 00667 (reflect.go:25)    PCDATA  $2, $6
0x029b 00667 (reflect.go:25)    LEAQ    24(SP), SI
0x02a0 00672 (reflect.go:25)    PCDATA  $2, $0
0x02a0 00672 (reflect.go:25)    DUFFCOPY    $826
0x02b3 00691 (reflect.go:25)    MOVBLZX 104(SP), AX
0x02b8 00696 (reflect.go:25)    MOVB    AL, ""..autotmp_92+115(SP)
0x02bc 00700 (reflect.go:25)    PCDATA  $2, $5
0x02bc 00700 (reflect.go:25)    PCDATA  $0, $10
0x02bc 00700 (reflect.go:25)    LEAQ    "".mymethod+2664(SP), DI
0x02c4 00708 (reflect.go:25)    PCDATA  $2, $6
0x02c4 00708 (reflect.go:25)    PCDATA  $0, $11
0x02c4 00708 (reflect.go:25)    LEAQ    ""..autotmp_91+2744(SP), SI
0x02cc 00716 (reflect.go:25)    PCDATA  $2, $0
0x02cc 00716 (reflect.go:25)    DUFFCOPY    $826
0x02df 00735 (reflect.go:25)    MOVBLZX ""..autotmp_92+115(SP), AX
0x02e4 00740 (reflect.go:25)    MOVB    AL, "".b+114(SP)
tt := (*interfaceType)(unsafe.Pointer(t))
type iface struct {
    tab  *itab
    data unsafe.Pointer
}

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.MethodByName()方法
    tt.MethodByName(name)
    interfaceType.methods保存了接口所有的方法。
//src\reflect\type.go
// imethod represents a method on an interface type
type imethod struct {
    name nameOff // name of method
    typ  typeOff // .(*FuncType) underneath
}

// interfaceType represents an interface type.
type interfaceType struct {
    rtype
    pkgPath name      // import path
    methods []imethod // sorted by hash
}

// src\runtime\type.go  与runtime变量名不同,结构完全一样
type interfacetype struct {
    typ     _type
    pkgpath name
    mhdr    []imethod
}





3.2.3 interfaceType.Method(i int) (m Method)

// Method returns the i'th method in the type's method set.
func (t *interfaceType) Method(i int) (m Method) {
    if i < 0 || i >= len(t.methods) {
        return
    }
    p := &t.methods[i]
    pname := t.nameOff(p.name)
    m.Name = pname.name()
    if !pname.isExported() {
        m.PkgPath = pname.pkgPath()
        if m.PkgPath == "" {
            m.PkgPath = t.pkgPath.name()
        }
    }
    m.Type = toType(t.typeOff(p.typ))
    m.Index = i
    return
}
  1. methods成员包含两个成员,name nameOff // name of methodtyp typeOff // .(*FuncType) underneath
  2. nameoff()函数,由运行时根据rtype变量地址,以及name偏移量计算出来。保存真正名字的位置。
  3. 如果名字一致,就返回该方法Method.
func (t *rtype) nameOff(off nameOff) name {
    return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}
}

// resolveNameOff resolves a name offset from a base pointer.
// The (*rtype).nameOff method is a convenience wrapper for this function.
// Implemented in the runtime package.
func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer
5   type person struct {
6         name string
7         age int32
8   }
21  var var_interface interface{} = person{name:"abc",age:18}
23  var var_type reflect.Type = reflect.TypeOf(var_interface)
     

对应汇编


0x00e0 00224 (reflect.go:23)    PCDATA  $2, $1
0x00e0 00224 (reflect.go:23)    MOVQ    "".var_interface+504(SP), AX
0x00e8 00232 (reflect.go:23)    PCDATA  $0, $1
0x00e8 00232 (reflect.go:23)    MOVQ    "".var_interface+496(SP), CX
0x00f0 00240 (reflect.go:23)    PCDATA  $0, $4
0x00f0 00240 (reflect.go:23)    MOVQ    CX, reflect.i+512(SP)   // 接口类型
0x00f8 00248 (reflect.go:23)    PCDATA  $2, $0
0x00f8 00248 (reflect.go:23)    MOVQ    AX, reflect.i+520(SP)   // 接口值
0x0100 00256 (reflect.go:23)    XORPS   X0, X0
0x0103 00259 (reflect.go:23)    MOVUPS  X0, "".~R0+352(SP)
0x010b 00267 (reflect.go:23)    XCHGL   AX, AX
0x010c 00268 (reflect.go:23)    XORPS   X0, X0
0x010f 00271 (reflect.go:23)    MOVUPS  X0, reflect.eface·3+672(SP)
// 对应源码 src\reflect\type.go
1374    func TypeOf(i interface{}) Type {
1375        eface := *(*emptyInterface)(unsafe.Pointer(&i))
1376        return toType(eface.typ)
1378    }

0x0117 00279 ($GOROOT/src/reflect/type.go:1375) PCDATA  $2, $1
0x0117 00279 ($GOROOT/src/reflect/type.go:1375) LEAQ    reflect.i+512(SP), AX
0x011f 00287 ($GOROOT/src/reflect/type.go:1375) PCDATA  $2, $0
0x011f 00287 ($GOROOT/src/reflect/type.go:1375) TESTB   AL, (AX)
0x0121 00289 ($GOROOT/src/reflect/type.go:1375) PCDATA  $2, $1
0x0121 00289 ($GOROOT/src/reflect/type.go:1375) MOVQ    reflect.i+520(SP), AX   //接口值
0x0129 00297 ($GOROOT/src/reflect/type.go:1375) PCDATA  $2, $3
0x0129 00297 ($GOROOT/src/reflect/type.go:1375) PCDATA  $0, $1
0x0129 00297 ($GOROOT/src/reflect/type.go:1375) MOVQ    reflect.i+512(SP), CX   //接口类型,eface.typ 即*rtype
0x0131 00305 ($GOROOT/src/reflect/type.go:1375) MOVQ    CX, reflect.eface·3+672(SP) //eface变量设置接口类型
0x0139 00313 ($GOROOT/src/reflect/type.go:1375) PCDATA  $2, $2
0x0139 00313 ($GOROOT/src/reflect/type.go:1375) MOVQ    AX, reflect.eface·3+680(SP) //eface变量设置接口值
0x0141 00321 ($GOROOT/src/reflect/type.go:1376) PCDATA  $2, $0
0x0141 00321 ($GOROOT/src/reflect/type.go:1376) PCDATA  $0, $5
0x0141 00321 ($GOROOT/src/reflect/type.go:1376) MOVQ    CX, reflect.t+128(SP)   //接口类型,首个元素
0x0149 00329 ($GOROOT/src/reflect/type.go:1376) XORPS   X0, X0
0x014c 00332 ($GOROOT/src/reflect/type.go:1376) MOVUPS  X0, "".~R0+448(SP)
0x0154 00340 ($GOROOT/src/reflect/type.go:1376) XCHGL   AX, AX

3003    func toType(t *rtype) Type {
3004        if t == nil {
3005            return nil
3006        }
3007        return t
3008    }

0x0155 00341 ($GOROOT/src/reflect/type.go:3004) CMPQ    reflect.t+128(SP), $0
0x015e 00350 (:0)       JNE     357
0x0160 00352 (:0)       JMP     3513
0x0165 00357 ($GOROOT/src/reflect/type.go:3007) PCDATA  $2, $1
0x0165 00357 ($GOROOT/src/reflect/type.go:3007) PCDATA  $0, $1
0x0165 00357 ($GOROOT/src/reflect/type.go:3007) MOVQ    reflect.t+128(SP), AX
0x016d 00365 ($GOROOT/src/reflect/type.go:3007) MOVQ    AX, ""..autotmp_45+216(SP)

0x0175 00373 ($GOROOT/src/reflect/type.go:1376) PCDATA  $2, $3
0x0175 00373 ($GOROOT/src/reflect/type.go:1376) LEAQ    go.itab.*reflect.rtype,reflect.Type(SB), CX //接口类型,即reflect.Type
0x017c 00380 ($GOROOT/src/reflect/type.go:1376) MOVQ    CX, ""..autotmp_48+1056(SP)
0x0184 00388 ($GOROOT/src/reflect/type.go:1376) MOVQ    AX, ""..autotmp_48+1064(SP)
0x018c 00396 ($GOROOT/src/reflect/type.go:1376) PCDATA  $2, $1
0x018c 00396 ($GOROOT/src/reflect/type.go:1376) PCDATA  $0, $6
0x018c 00396 ($GOROOT/src/reflect/type.go:1376) MOVQ    CX, "".~R0+448(SP)  //返回接口类型
0x0194 00404 ($GOROOT/src/reflect/type.go:1376) PCDATA  $2, $0
0x0194 00404 ($GOROOT/src/reflect/type.go:1376) MOVQ    AX, "".~R0+456(SP)  //返回接口值
0x019c 00412 ($GOROOT/src/reflect/type.go:1376) JMP     414
0x019e 00414 (reflect.go:23)    MOVQ    "".~R0+448(SP), AX
0x01a6 00422 (reflect.go:23)    PCDATA  $2, $2
0x01a6 00422 (reflect.go:23)    PCDATA  $0, $1
0x01a6 00422 (reflect.go:23)    MOVQ    "".~R0+456(SP), CX
0x01ae 00430 (reflect.go:23)    MOVQ    AX, ""..autotmp_49+1040(SP) //临时变量,接口类型
0x01b6 00438 (reflect.go:23)    MOVQ    CX, ""..autotmp_49+1048(SP) //临时变量,接口值
0x01be 00446 (reflect.go:23)    MOVQ    AX, "".~R0+352(SP)
0x01c6 00454 (reflect.go:23)    MOVQ    CX, "".~R0+360(SP)
0x01ce 00462 (reflect.go:23)    JMP     464
0x01d0 00464 (reflect.go:23)    PCDATA  $0, $7
0x01d0 00464 (reflect.go:23)    MOVQ    AX, "".var_type+480(SP) 
0x01d8 00472 (reflect.go:23)    PCDATA  $2, $0
0x01d8 00472 (reflect.go:23)    MOVQ    CX, "".var_type+488(SP)
fmt.Println("type:",reflect.TypeOf(var_type));
//输出:type: *reflect.rtype
20  var var_person person = person{name:"abc",age:18}
23  var var_type reflect.Type = reflect.TypeOf(var_person)
25  method,b := var_type.MethodByName("Test_MethodByName1")
27  numMethod := var_type.NumMethod()

25行调用MethodByName对应汇编

        0x023d 00573 (reflect.go:25)    PCDATA  $2, $5
        0x023d 00573 (reflect.go:25)    LEAQ    ""..autotmp_79+2416(SP), DI
        0x0245 00581 (reflect.go:25)    XORPS   X0, X0
        0x0248 00584 (reflect.go:25)    PCDATA  $2, $0
        0x0248 00584 (reflect.go:25)    LEAQ    -48(DI), DI
        0x024c 00588 (reflect.go:25)    DUFFZERO        $277
        0x025f 00607 (reflect.go:25)    MOVQ    "".var_type+840(SP), AX
        0x0267 00615 (reflect.go:25)    TESTB   AL, (AX)
        
        0x0269 00617 (reflect.go:25)    MOVQ    176(AX), AX  // 将MethodByName方法地址放入 AX,var_type变量向后偏移176位置
                                                             //见下方 go.itab.*reflect.rtype,reflect.Type SRODATA dupok size=272
                                                             // rel 176+8 t=1 reflect.(*rtype).MethodByName+0
                                                        
        0x0270 00624 (reflect.go:25)    PCDATA  $2, $2
        0x0270 00624 (reflect.go:25)    MOVQ    "".var_type+848(SP), CX
        0x0278 00632 (reflect.go:25)    PCDATA  $2, $0
        0x0278 00632 (reflect.go:25)    MOVQ    CX, (SP)
        0x027c 00636 (reflect.go:25)    PCDATA  $2, $2
        0x027c 00636 (reflect.go:25)    LEAQ    go.string."Test_MethodByName1"(SB), CX
        0x0283 00643 (reflect.go:25)    PCDATA  $2, $0
        0x0283 00643 (reflect.go:25)    MOVQ    CX, 8(SP)
        0x0288 00648 (reflect.go:25)    MOVQ    $18, 16(SP)
        0x0291 00657 (reflect.go:25)    CALL    AX      // 调用MethodByName方法
        0x0293 00659 (reflect.go:25)    PCDATA  $2, $5
        0x0293 00659 (reflect.go:25)    PCDATA  $0, $9
        0x0293 00659 (reflect.go:25)    LEAQ    ""..autotmp_79+2416(SP), DI
        0x029b 00667 (reflect.go:25)    PCDATA  $2, $6
        0x029b 00667 (reflect.go:25)    LEAQ    24(SP), SI
        0x02a0 00672 (reflect.go:25)    PCDATA  $2, $0
        0x02a0 00672 (reflect.go:25)    DUFFCOPY        $826
        0x02b3 00691 (reflect.go:25)    MOVBLZX 104(SP), AX
        0x02b8 00696 (reflect.go:25)    MOVB    AL, ""..autotmp_80+115(SP)
        0x02bc 00700 (reflect.go:25)    PCDATA  $2, $5
        0x02bc 00700 (reflect.go:25)    PCDATA  $0, $10
        0x02bc 00700 (reflect.go:25)    LEAQ    "".method+2336(SP), DI
        0x02c4 00708 (reflect.go:25)    PCDATA  $2, $6
        0x02c4 00708 (reflect.go:25)    PCDATA  $0, $11
        0x02c4 00708 (reflect.go:25)    LEAQ    ""..autotmp_79+2416(SP), SI
        0x02cc 00716 (reflect.go:25)    PCDATA  $2, $0
        0x02cc 00716 (reflect.go:25)    DUFFCOPY        $826
        0x02df 00735 (reflect.go:25)    MOVBLZX ""..autotmp_80+115(SP), AX
        0x02e4 00740 (reflect.go:25)    MOVB    AL, "".b+114(SP)
//src\runtime\runtime2.go
type itab struct {
    inter *interfacetype    //8 字节
    _type *_type            //8 字节
    hash  uint32   //4 字节 copy of _type.hash. Used for type switches.
    _     [4]byte   //4 字节
    fun   [1]uintptr // 8 字节variable sized. fun[0]==0 means _type does not implement inter.
}
go.itab.*reflect.rtype,reflect.Type SRODATA dupok size=272
        0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0010 d6 c9 33 e3 00 00 00 00 00 00 00 00 00 00 00 00  ..3.............
        0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x00a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x00b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x00c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x00d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x00e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x00f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        rel 0+8 t=1 type.reflect.Type+0     // itab.inter 接口类型
        rel 8+8 t=1 type.*reflect.rtype+0   // itab._type 动态类型,即reflect.rtype
        rel 24+8 t=1 reflect.(*rtype).Align+0   //itab.fun
        rel 32+8 t=1 reflect.(*rtype).AssignableTo+0
        rel 40+8 t=1 reflect.(*rtype).Bits+0
        rel 48+8 t=1 reflect.(*rtype).ChanDir+0
        rel 56+8 t=1 reflect.(*rtype).Comparable+0
        rel 64+8 t=1 reflect.(*rtype).ConvertibleTo+0
        rel 72+8 t=1 reflect.(*rtype).Elem+0
        rel 80+8 t=1 reflect.(*rtype).Field+0
        rel 88+8 t=1 reflect.(*rtype).FieldAlign+0
        rel 96+8 t=1 reflect.(*rtype).FieldByIndex+0
        rel 104+8 t=1 reflect.(*rtype).FieldByName+0
        rel 112+8 t=1 reflect.(*rtype).FieldByNameFunc+0
        rel 120+8 t=1 reflect.(*rtype).Implements+0
        rel 128+8 t=1 reflect.(*rtype).In+0
        rel 136+8 t=1 reflect.(*rtype).IsVariadic+0
        rel 144+8 t=1 reflect.(*rtype).Key+0
        rel 152+8 t=1 reflect.(*rtype).Kind+0
        rel 160+8 t=1 reflect.(*rtype).Len+0
        rel 168+8 t=1 reflect.(*rtype).Method+0
        rel 176+8 t=1 reflect.(*rtype).MethodByName+0   //偏移176位置为MethodByName方法地址
        rel 184+8 t=1 reflect.(*rtype).Name+0
        rel 192+8 t=1 reflect.(*rtype).NumField+0
        rel 200+8 t=1 reflect.(*rtype).NumIn+0
        rel 208+8 t=1 reflect.(*rtype).NumMethod+0  //偏移208位置为NumMethod方法地址
        rel 216+8 t=1 reflect.(*rtype).NumOut+0
        rel 224+8 t=1 reflect.(*rtype).Out+0
        rel 232+8 t=1 reflect.(*rtype).PkgPath+0
        rel 240+8 t=1 reflect.(*rtype).Size+0
        rel 248+8 t=1 reflect.(*rtype).String+0
        rel 256+8 t=1 reflect.(*rtype).common+0
        rel 264+8 t=1 reflect.(*rtype).uncommon+0

3.2. 不是接口变量,转换为uncommonType类型

  1. 根据变量的实际类型

// uncommonType is present only for defined types or types with methods
// (if T is a defined type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe a non-defined type with no methods.
type uncommonType struct {
    pkgPath nameOff // import path; empty for built-in types like int, string
    mcount  uint16  // number of methods
    xcount  uint16  // number of exported methods
    moff    uint32  // offset from this uncommontype to [mcount]method
    _       uint32  // unused
}


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