为什么要命名返回参数?

use*_*828 37 go

命名函数的返回参数会带来什么好处?

func namedReturn(i int) (ret int) {
    ret = i
    i += 2
    return
}

func anonReturn(i int) int {
    ret := i
    i += 2
    return ret
}
Run Code Online (Sandbox Code Playgroud)

Tho*_*ler 40

命名它们有一些好处:

  • 它作为文件.
  • 它们被自动声明并初始化为零值.
  • 如果您有多个返回站点,则在更改函数的返回值时不需要更改它们,因为它只会说"返回".

还有一些缺点,主要是通过声明一个同名变量很容易意外地影响它们.


Effective Go有一个关于命名结果参数部分:

Go函数的返回或结果"参数"可以给出名称并用作常规变量,就像传入参数一样.命名时,它们在函数开始时被初始化为其类型的零值; 如果函数执行不带参数的return语句,则结果参数的当前值将用作返回值.

名称不是强制性的,但它们可以使代码更短更清晰:它们是文档.如果我们命名nextInt的结果,很明显哪个返回int是哪个.

func nextInt(b []byte, pos int) (value, nextPos int) {
Run Code Online (Sandbox Code Playgroud)

[...]

  • 暗影是一个主要问题.我经常有这样的事情:`我,错误:= strconv.Atoi(...)`.`i`是一个局部变量,但我希望错误是一个返回值.为了使这个工作,我必须在之前声明我,而不是使用:= (11认同)

Son*_*nia 21

命名返回变量的另一个特殊用途是由延迟函数文字捕获.一个简单的例子:

package main

import (
    "errors"
    "fmt"
)

func main() {
    fmt.Println(f())
}

var harmlessError = errors.New("you should worry!")

func f() (err error) {
    defer func() {
        if err == harmlessError {
            err = nil
        }
    }()
    return harmlessError
}
Run Code Online (Sandbox Code Playgroud)

输出是<nil>.在更实际的场景中,延迟函数可以处理恐慌,并且除了错误结果之外还可以修改其他返回值.然而,共同的魔力是延迟文字有机会在f终止后修改f的返回值,无论是正常还是恐慌.


Fre*_*Foo 5

它至少在两种情况下很有用:

  1. 每当您必须声明要返回的变量时。例如

    func someFunc() (int, error) {
        var r int
        var e error
        ok := someOtherFunc(&r)  // contrived, I admit
        if !ok {
            return r, someError()
        }
        return r, nil
    }
    
    Run Code Online (Sandbox Code Playgroud)

    func someFunc() (r int, e error) {
        ok := someOtherFunc(&r)
        if !ok {
            e = someError()
        }
        return
    }
    
    Run Code Online (Sandbox Code Playgroud)

    随着函数执行路径数量的增加,这一点变得更加重要。

  2. 当您记录返回值并希望按名称引用它们时。godoc将返回变量视为函数签名的一部分。

  • 第一个示例中未使用“e”。 (2认同)