go语言函数如何传递interface

如何传递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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,853评论 0 9
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,826评论 18 399
  • 1、interface 是一种类型 type I interface {Get() int} 首先interfac...
    Uzero阅读 2,622评论 0 2
  • 父母也是有“有效期”的。如果在孩子最初的十年父母忽略了教养,将来孩子再怎么叛逆,父母也只有摇头叹息了。 最近去拜访...
    虚怀若谷8阅读 556评论 0 0
  • 迟剑回头看听香惊魂未定的模样,心想杨姐姐为了救我,不惜深入虎穴,结果被耶律大石所困,是何等英雄气概。我便为这小姑娘...
    海墨I阅读 481评论 0 0