是否命名返回片需要在Go中初始化?



假设如下函数:

func returnNamedSlice(num int) (s []int)

我可以直接在代码中执行以下操作,就好像s已经完成了一样。

s = append(s, 5)

但如果我不做以上(append操作),那么s总是nil,返回的s也是nil

为什么这样设计?这似乎很不一致。

命名返回片初始化为nil。下面的语句之所以有效,是因为append函数处理nil片的方式与处理空片的方式相同。

s = append(s, 5)

Nil切片的处理方式与空切片相同,因为Nil切片的长度和容量被定义为零,与空切片相同。

该特性与命名返回值无关。下面是一个没有返回值的示例:

var x []int           // x is a nil slice of int
fmt.Println(x)        // prints []
fmt.Println(x == nil) // prints true
x = append(x, 5)      // x is slice with one element, 5
fmt.Println(x)        // prints [5]
fmt.Println(x == nil) // prints false

在检查这些特性时,一个令人困惑的地方是fmt包以相同的表示方式打印nil片和空片,[]

你也可以在nil切片中添加项,不管它是否为nil

看下面的例子:

package main
import "log"
func main() {
a := a() // no matter it returns nil 
log.Println("Is a nil: ", a == nil)
a = append(a, 1) // you can append items to nil slice
log.Println(a)
//
b := b()
b = append(b, 2)
log.Println(b)
}
func a() (s []int) {
return
}
func b() (s []int) {
s = append(s, 5)
return
}

和结果:

2022/06/19 09:52:02 Is a nil:  true
2022/06/19 09:52:02 [1]
2022/06/19 09:52:02 [5 2]

Go中的任何命名返回变量(规范中称之为"结果参数")都是"预初始化"的。到适当的零值,与任何没有初始化式的本地定义变量完全相同:

var i int
var f float64
var s string

i为0 (integer),f为0 (0.0, float64),s为" 0 "(空字符串"")。这就是你的函数:

func returnNamedSlice(num int) (s []int) {
// ... code here ...
return
}

在函数的顶部,// code here代码所在的地方,s初始化为"零",即[]int(nil):nil转换为[]int。这在Go规范的Return语句部分中有描述。

必须设置s非空值返回非空值。您不必使用append,但它是相当标准的附加到适当类型的nil,因为这使得它很容易在循环中建立一个列表或一系列if测试或其他:

if conditionA {
s = append(s, 42)
}
if conditionB {
s = append(s, 6, 9)
}

但:

if conditionC {
s = []int{3, 1, 4, 1, 5, 9}
}

也可以。

无论s最后被设置为什么,这就是它在返回时所持有的值。注意:

return someval

表示(1)将值赋值给s,然后(2)返回(按此顺序)。如果延迟函数随后调用panic,则有一个panic处理程序捕获panic并使用s和/或将值赋给s,这很重要;参见规范中的Defer语句示例。

最新更新