duanjian4150 2013-10-05 06:19
浏览 43
已采纳

Go中命名返回变量的预期用途是什么?

I find the provision of named returned variables in Go to be a useful feature, because it can avoid the separate declaration of a variable or variables. However, in some instances I want to return a different variable to the variable declared in the function as the return-variable. That appears to work ok, however I do find it a little strange to declare a return variable and then return something else.

While writing a test program to help learn Go (not the one below), I found it a little annoying specifying the return variable in the return statement of functions returning multiple variables. Particularly so, because the variables had been named in the function declaration. I now find while posting this, that it appears that where there are named return variables, they don't need to be used in the return statement, just "return" will suffice and will implicitly use the named variables. That I find this a great feature.

So, although I have possibly partly answered my own question, could someone advise if my usage below is acceptable? I'm sure this is documented, but I haven't come across it, and it doesn't appear to be in the reference-book that I purchased which I think overlooks this feature.

Basically, the rule appears to be (as far as I can determine), that where named return variables are used, that the function statement declares the variables, and also the function can optionally implicitly uses them as the return values, however this can be overridden by using explicit return values.

Example Program :

package main

func main() {
    var sVar1, sVar2 string
    println("Test Function return-values")
    sVar1, sVar2 = fGetVal(1)
    println("This was returned for '1' : " + sVar1 + ", " + sVar2)
    sVar1, sVar2 = fGetVal(2)
    println("This was returned for '2' : " + sVar1 + ", " + sVar2)
}

func fGetVal(iSeln int) (sReturn1 string, sReturn2 string) {
    sReturn1 = "This is 'sReturn1'"
    sReturn2 = "This is 'sReturn2'"

    switch iSeln {
        case 1  :  return
        default : return "This is not 'sReturn1'", "This is not 'sReturn2'"
    }
}
  • 写回答

3条回答 默认 最新

  • douyi3767 2013-10-05 07:25
    关注

    Your usage is absolutely fine and you'll find plenty of similar examples in the Go source code.

    I'll attempt to explain how the return statement actually works in Go to give a deeper appreciation of why. It is useful to have a think about how Go implements parameter passing and return from functions. Once you understand that you'll understand why named return variables are so natural.

    All arguments to functions and all return values from functions are passed on the stack in Go. This varies from C which usually passes some parameters in registers. When a function is called in Go the caller makes space on the stack for both the arguments and the return values then calls the function.

    Specifically, when this function is called, which has 3 input parameters a, b, c and two return values

    func f(a int, b int, c int) (int, int)
    

    The stack will look like this (low memory address at the top)

    * a
    * b
    * c
    * space for return parameter 1
    * space for return parameter 2
    

    Now it is obvious that naming your return parameter just names those locations on the stack.

    func f(a int, b int, c int) (x int, y int)
    
    * a
    * b
    * c
    * x
    * y
    

    It should now also be obvious what an empty return statement does - it just returns to the caller with whatever the values of x and y are.

    Now for some disassembly! Compiling this with go build -gcflags -S test.go

    package a
    
    func f(a int, b int, c int) (int, int) {
        return a, 0
    }
    
    func g(a int, b int, c int) (x int, y int) {
        x = a
        return
    }
    

    Gives

    --- prog list "f" ---
    0000 (test.go:3) TEXT    f+0(SB),$0-40
    0001 (test.go:3) LOCALS  ,$0
    0002 (test.go:3) TYPE    a+0(FP){int},$8
    0003 (test.go:3) TYPE    b+8(FP){int},$8
    0004 (test.go:3) TYPE    c+16(FP){int},$8
    0005 (test.go:3) TYPE    ~anon3+24(FP){int},$8
    0006 (test.go:3) TYPE    ~anon4+32(FP){int},$8
    0007 (test.go:4) MOVQ    a+0(FP),BX
    0008 (test.go:4) MOVQ    BX,~anon3+24(FP)
    0009 (test.go:4) MOVQ    $0,~anon4+32(FP)
    0010 (test.go:4) RET     ,
    
    --- prog list "g" ---
    0011 (test.go:7) TEXT    g+0(SB),$0-40
    0012 (test.go:7) LOCALS  ,$0
    0013 (test.go:7) TYPE    a+0(FP){int},$8
    0014 (test.go:7) TYPE    b+8(FP){int},$8
    0015 (test.go:7) TYPE    c+16(FP){int},$8
    0016 (test.go:7) TYPE    x+24(FP){int},$8
    0017 (test.go:7) TYPE    y+32(FP){int},$8
    0018 (test.go:7) MOVQ    $0,y+32(FP)
    0019 (test.go:8) MOVQ    a+0(FP),BX
    0020 (test.go:8) MOVQ    BX,x+24(FP)
    0021 (test.go:9) RET     ,
    

    Both functions assemble to pretty much the same code. You can see quite clearly the declarations of a,b,c,x,y on the stack in g, though in f, the return values are anonymous anon3 and anon4.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题
  • ¥30 python代码,帮调试,帮帮忙吧
  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建