假设如下函数:
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语句示例。