Golang语言社区go学习代码世界

go语言函数如何传递interface

2017-09-07  本文已影响30人  CodingCode

如何传递interface

package main

import (
    "fmt"
)

type MyInterface interface {
   foo()
}

type MyStruct struct {
   i1 int64
}

func (m MyStruct) foo() {
   fmt.Println("i1:", m.i1)
}

func Hello1(p interface{}) {
}

func Hello2(p MyInterface) {
   p.foo()
}

func main() {
   var i int
   var m MyStruct

   Hello1(i)
   Hello1(m)

   Hello2(m)
}

我们看main函数如何调用hello1和hello2的

Hello1(i)

   Hello1(i)
  47c055:   48 8b 44 24 28          mov    0x28(%rsp),%rax              # move i value to %rax
  47c05a:   48 89 44 24 40          mov    %rax,0x40(%rsp)              # copy i value to 0x40(%rsp) as parameter
  47c05f:   48 8d 05 3a e8 00 00    lea    0xe83a(%rip),%rax            # 48a8a0 <type.*+0xd8a0>
  47c066:   48 89 04 24             mov    %rax,(%rsp)                  # move i type address to 0(%rsp)
  47c06a:   48 8d 44 24 40          lea    0x40(%rsp),%rax              # move 0x40 + %rsp (i.e., copy i address) to %rax
  47c06f:   48 89 44 24 08          mov    %rax,0x8(%rsp)               # move copy i address to 9(%rax)
  47c074:   e8 f7 f8 f8 ff          callq  40b970 <runtime.convT2E>     # call runtime.convT2E, empty interface
  47c079:   48 8b 44 24 18          mov    0x18(%rsp),%rax              
  47c07e:   48 8b 4c 24 10          mov    0x10(%rsp),%rcx
  47c083:   48 89 0c 24             mov    %rcx,(%rsp)                  # prepare interface parameter in (%rsp), pointer to type information
  47c087:   48 89 44 24 08          mov    %rax,0x8(%rsp)               # prepare interface parameter in (%rsp), pointer to value
  47c08c:   e8 5f f8 ff ff          callq  47b8f0 <main.Hello1>

这个逻辑很清楚,变量i是一个整数,Hello1接收一个interface,这就需要把i转变成interface,然后再调用Hello1,这个转变的过程就由runtime.convT2E/convT2I来完成。

系统函数convT2E/convT2I的定义如下(根据是interface还是empty,分别调用)。
函数 runtime.convT2E,通常负责将一个变量换成 empty interface,即interface{},函数convT2I将负责把一个变量换成一个指定的non-empty interface,比如在我们例子中MyInterface。
convT2E/convT2I都是返回一个interface对象,这个对象包含两个指针共16字节,一个指向变量的类型信息地址,一个指向变量的值地址。

func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
    ...
  
    x := newobject(t)
    typedmemmove(t, x, elem)
    e._type = t
    e.data = x
    return
}

func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
    t := tab._type
    
    ...
  
    x := newobject(t)
    typedmemmove(t, x, elem)
    i.tab = tab
    i.data = x
    return
}

Hello1(m)

Hello1(m)和Hello1(i)是一样的过程。

   Hello1(m)
  47c091:   48 8b 44 24 20          mov    0x20(%rsp),%rax              # move m.i1 value to %rax
  47c096:   48 89 44 24 38          mov    %rax,0x38(%rsp)              # copy m.i1 value to 0x38(%rsp) as parameter
  47c09b:   48 8d 05 9e 73 01 00    lea    0x1739e(%rip),%rax           # 493440 <type.*+0x16440>
  47c0a2:   48 89 04 24             mov    %rax,(%rsp)
  47c0a6:   48 8d 44 24 38          lea    0x38(%rsp),%rax
  47c0ab:   48 89 44 24 08          mov    %rax,0x8(%rsp)
  47c0b0:   e8 bb f8 f8 ff          callq  40b970 <runtime.convT2E>
  47c0b5:   48 8b 44 24 10          mov    0x10(%rsp),%rax
  47c0ba:   48 8b 4c 24 18          mov    0x18(%rsp),%rcx
  47c0bf:   48 89 04 24             mov    %rax,(%rsp)
  47c0c3:   48 89 4c 24 08          mov    %rcx,0x8(%rsp)
  47c0c8:   e8 23 f8 ff ff          callq  47b8f0 <main.Hello1>

Hello2(m)

Hello2(m)和Hello1(m)也大体类似,除了使用convT2I去转换一个具体的interface类型。

   Hello2(m)
  47c0cd:   48 8b 44 24 20          mov    0x20(%rsp),%rax
  47c0d2:   48 89 44 24 30          mov    %rax,0x30(%rsp)
  47c0d7:   48 8d 05 02 b1 07 00    lea    0x7b102(%rip),%rax           # 4f71e0 <go.itab.main.MyStruct,main.MyInterface>
  47c0de:   48 89 04 24             mov    %rax,(%rsp)
  47c0e2:   48 8d 44 24 30          lea    0x30(%rsp),%rax
  47c0e7:   48 89 44 24 08          mov    %rax,0x8(%rsp)
  47c0ec:   e8 2f f9 f8 ff          callq  40ba20 <runtime.convT2I>     # here is the difference with interface, convT2I vs. convT2E
  47c0f1:   48 8b 44 24 10          mov    0x10(%rsp),%rax
  47c0f6:   48 8b 4c 24 18          mov    0x18(%rsp),%rcx
  47c0fb:   48 89 04 24             mov    %rax,(%rsp)
  47c0ff:   48 89 4c 24 08          mov    %rcx,0x8(%rsp)
  47c104:   e8 27 fb ff ff          callq  47bc30 <main.Hello2>

有一个关于interface的介绍文档供参考
https://research.swtch.com/interfaces

上一篇 下一篇

猜你喜欢

热点阅读