0x000000000(./src/main.go:30) MOVQ (TLS), CX
0x000900009(./src/main.go:30) CMPQ SP, 16(CX)
0x000d00013(./src/main.go:30) JLS 157
0x001300019(./src/main.go:30) SUBQ $80, SP
0x001700023(./src/main.go:30) MOVQ BP, 72(SP)
0x001c00028(./src/main.go:30) LEAQ 72(SP), BP
0x002100033(./src/main.go:30) FUNCDATA$0, gclocals·69c1753bd5f81501d95132d08af04464(SB)
0x002100033(./src/main.go:30) FUNCDATA$1, gclocals·e226d4ae4a7cad8835311c6a4683c14f(SB)
0x002100033(./src/main.go:31) MOVQ $18, ""..autotmp_1+48(SP)
0x002a00042(./src/main.go:31) LEAQ go.itab."".Student,"".Person(SB), AX
0x003100049(./src/main.go:31) MOVQ AX, (SP)
0x003500053(./src/main.go:31) LEAQ ""..autotmp_1+48(SP), AX
0x003a00058(./src/main.go:31) MOVQ AX, 8(SP)
0x003f00063(./src/main.go:31) PCDATA $0, $0
0x003f00063(./src/main.go:31) CALL runtime.convT2I64(SB)
0x004400068(./src/main.go:31) MOVQ 24(SP), AX
0x004900073(./src/main.go:31) MOVQ 16(SP), CX
0x004e00078(./src/main.go:33) TESTQ CX, CX
0x005100081(./src/main.go:33) JEQ 87
0x005300083(./src/main.go:33) MOVQ 8(CX), CX
0x005700087(./src/main.go:33) MOVQ $0, ""..autotmp_2+56(SP)
0x006000096(./src/main.go:33) MOVQ $0, ""..autotmp_2+64(SP)
0x006900105(./src/main.go:33) MOVQ CX, ""..autotmp_2+56(SP)
0x006e00110(./src/main.go:33) MOVQ AX, ""..autotmp_2+64(SP)
0x007300115(./src/main.go:33) LEAQ ""..autotmp_2+56(SP), AX
0x007800120(./src/main.go:33) MOVQ AX, (SP)
0x007c00124(./src/main.go:33) MOVQ $1, 8(SP)
0x008500133(./src/main.go:33) MOVQ $1, 16(SP)
0x008e00142(./src/main.go:33) PCDATA $0, $1
0x008e00142(./src/main.go:33) CALL fmt.Println(SB)
0x009300147(./src/main.go:34) MOVQ 72(SP), BP
0x009800152(./src/main.go:34) ADDQ $80, SP
0x009c00156(./src/main.go:34) RET
0x009d00157(./src/main.go:34) NOP
0x009d00157(./src/main.go:30) PCDATA $0, $-1
deb hardy main restricted deb-src hardy main restricted deb hardy-updates main restricted deb-src hardy-updates main restricted deb hardy universe deb-src hardy universe deb hardy-updates universe deb-src hardy-updates universe deb hardy multiverse deb-src hardy multiverse deb hardy-updates multiverse deb-src hardy-updates multiverse deb hardy-security main restricted deb-src hardy-security main restricted deb hardy-security universe deb-src hardy-security universe deb hardy-security multiverse deb-src hardy-security multiverse。//重定向so目录为src/main/libs和src/main/jnilibs,原来为src/main/jnilibs。20 call runtime·entersyscall(sb)。
0x00a200162(./src/main.go:30) JMP 0
我们从第 10 行开始看,如果不理解前面几行汇编代码的话,可以回去看看公众号前面两篇文章,这里我就省略了。
汇编行数
操作
10-14
构造调用 runtime.convT2I64(SB) 的参数
我们来看下这个函数的参数形式:
funcconvT2I64(tab *itab, elem unsafe.Pointer)(i iface){ // ……}
convT2I64 会构造出一个 inteface,也就是我们的 Person 接口。
第一个参数的位置是 (SP),这里被赋上了 go.itab."".Student,"".Person(SB) 的地址。
我们从生成的汇编找到:
go.itab."".Student,"".Person SNOPTRDATA dupok size=40
0x000000000000000000000000000000000000
0x00100000000000000000da 9f20d4
rel 0+8t=1type."".Person+0
rel 8+8t=1type."".Student+0
size=40 大小为40字节,回顾一下:
typeitab struct{
inter *interfacetype // 8字节
_type *_type // 8字节
link *itab // 8字节
hash uint32// 4字节
bad bool// 1字节
inhash bool// 1字节
unused [2]byte// 2字节
fun [1]uintptr// variable sized // 8字节
}
把每个字段的大小相加,itab 结构体的大小就是 40 字节。上面那一串数字实际上是 itab 序列化后的内容,注意到大部分数字是 0,从 24 字节开始的 4 个字节 da 9f 20 d4 实际上是 itab 的 hash 值,这在判断两个类型是否相同的时候会用到。
下面两行是链接指令,简单说就是将所有源文件综合起来,给每个符号赋予一个全局的位置值。这里的意思也比较明确:前8个字节最终存储的是 type."".Person 的地址,对应 itab 里的 inter 字段,表示接口类型;8-16 字节最终存储的是 type."".Student 的地址,对应 itab 里 _type 字段,表示具体类型。
第二个参数就比较简单了,它就是数字 18 的地址,这也是初始化 Student 结构体的时候会用到。
汇编行数
操作
15
调用 runtime.convT2I64(SB)
具体看下代码:
return(*c.char)(unsafe.pointer(c.cbytes(dataslice))), len(dataslice)。c.creportdata(callbackfunc, (*c.char)(unsafe.pointer(&data[0])), c.int(len(data)))。c.free(unsafe.pointer(cmsg))。
t := tab._type
//...
varx unsafe.Pointer
if*(*uint64)(elem) == 0{
x = unsafe.Pointer(&zeroVal[0])
} else{
x = mallocgc(8, t, false)
*(*uint64)(x) = *(*uint64)(elem)
}
i.tab = tab
i.data = x
return
}
这块代码比较简单,把 tab 赋给了 iface 的 tab 字段;data 部分则是在堆上申请了一块内存,然后将 elem 指向的 18 拷贝过去。这样 iface 就组装好了。
汇编行数
操作
17
把 i.tab 赋给 CX
18
把 i.data 赋给 AX
19-21
检测 i.tab 是否是 nil,如果不是的话,把 CX 移动 8 个字节,也就是把 itab 的 _type 字段赋给了 CX,这也是接口的实体类型,最终要作为 fmt.Println 函数的参数
后面,就是调用 fmt.Println 函数及之前的参数准备工作了,不再赘述。
这样,我们就把一个 interface 的构造过程说完了。
【引申1】 如何打印出接口类型的 Hash 值?
这里参考曹大神翻译的一篇文章,参考资料里会写上。具体做法如下:
typeiface struct{
tab *itab
data unsafe.Pointer
}
typeitab struct{
inter uintptr
_type uintptr
link uintptr
hash uint32

_ [4]byte
fun [1]uintptr
}
funcmain(){
varqcrao = Person(Student{age: 18})
iface := (*iface)(unsafe.Pointer(&qcrao))
fmt.Printf("iface.tab.hash = %#xn", iface.tab.hash)
}
了一个山寨版的 iface 和 itab,说它山寨是因为 itab 里的一些关键数据结构都不具体展开了,比如 _type,对比一下正宗的定义就可以发现,但是山寨版依然能工作,因为 _type 就是一个指针而已嘛。
在 main 函数里,先构造出一个接口对象 qcrao,然后强制类型转换,最后读取出 hash 值,非常妙!你也可以自己动手试一下。
运行结果:
iface.tab.hash = 0xd4209fda
值得一提的是,构造接口 qcrao 的时候,即使我把 age 写成其他值,得到的 hash 值依然不变的,这应该是可以预料的,hash 值只和他的字段、方法相关。
类型转换和断言的区别
我们知道,Go 语言中不允许隐式类型转换,也就是说 = 两边,不允许出现类型不相同的变量。
该代码的注意点:maketrans()为制作规则,之后translate()进行转换,如果只是转换没有做重新赋值的操作,对于变量本身是不会有影响的,包括上文的upper/lower等也是如此。应该先选择value类别,而不是control强制该变量类型为int型,然后在变量类型中选择int、cstring型.在自定义变量名.这样强制的转换就会造成具体的错误.。针对接口编程的意思是针对超类型编程——变量的声明类型应该是超类,通常是一个抽象类或者一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量,这也意味着,声明类时不用理会以后执行时的真正对象类型。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-98808-2.html
全国人民都对台独势力恨之入骨
总局盯着小米电源查一段时间
帅
谁也不会像喝可乐一样和它