return 返回具体类型和interface{}时遇到的问题

zhaozonglu · 2018-05-28 19:07:34 · 1008 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2018-05-28 19:07:34 的主题,其中的信息可能已经有所发展或是发生改变。

两段代码

第一段:

func main() {
    a, b := testDemo()
    fmt.Println(a, b)
}

func testDemo() (int, int) {
    var a int
    return a, change(&a)
}

func change(a *int) int {
    *a++
    return 2
}

打印的结果是1 2

第二段代码

func main() {
    a, b := testDemo()
    fmt.Println(a, b)
}

func testDemo() (interface{}, int) {
    var a int
    return a, change(&a)
}

func change(a *int) int {
    *a++
    return 2
}

打印的结果是0 2

唯一的不同是testDemo这个函数的返回值是int还是interface{}

请教下为什么会有这样的不同呢?


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1008 次点击  
加入收藏 微博
1 回复  |  直到 2018-05-29 11:39:59
birdkiller
birdkiller · #1 · 7年之前

####你这个问题其实包含两个问题: 1.其实你的第二段代码并非你所写的情况,编译器识别的testDemo函数应该是 ···func testDemo() (interface{}, int) { var a int return interface{}(a), change(&a) }··· 只不过你写代码时省略了 interface{}(a)这个转化过程,但是编译器会帮你补上(暂时这么理解,其实是运行时执行的),这样它按照从左到右的顺序执行返回值,会先执行 interface{}(a),再执行change函数,然后赋值给return。 而你的第一段代码中并不需要执行 interface{}(a),所以会先执行change函数,然后赋值给return。 2.你的第一个返回值都不是传指针类型,所以不存在后执行的change函数给已存在的变量a重新赋值的问题。 具体证明你可以打开debug模式,单行调试,涉及interface{}参数或返回值(你的程序中两处:打印和testDemo)的地方,你会发现调用了runtime包下iface.go里的转化代码,涉及本代码二使用的是runtime.convT2E64(注释:// The convXXX functions are guaranteed by the compiler to succeed.说明此函数由编译器保证其正常执行)此时你再看作为值得elem参数,其存储之地址和调用前a的地址已经不一致,说明已经发生过数据拷贝,再结合266-267行x = mallocgc(8, t, false) *(*uint64)(x) = *(*uint64)(elem)又申请一块新内存(uint64),可知虽然你的change返回地址,却因为编译器的原因已不可能越过以上代码返回到testDemo外层。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传