英文:
Does the named return slice need to be initialized with make in Go?
问题
假设有这样一个函数:
func returnNamedSlice(num int) (s []int)
我可以直接在代码中执行以下操作,就好像s
已经被创建了一样。
s = append(s, 5)
但是如果我不执行上述的append
操作,那么s
始终为nil
,返回的s
也是nil
。
为什么会设计成这样?这看起来非常不一致。
英文:
Suppose a function such as:
func returnNamedSlice(num int) (s []int)
I am able to do the following directly in the code, as if s was already made.
s = append(s, 5)
But if I don't do the above (append
operation), then s
is always nil
and the returned s
is also nil
.
Why this design? This seems very inconsistent.
答案1
得分: 3
命名返回切片被初始化为nil。以下语句有效,因为append
函数对待nil切片和空切片的方式相同。
s = append(s, 5)
由于nil切片的长度和容量都定义为零,所以处理nil切片和空切片的方式相同。
这个特性与命名返回值无关。以下是一个没有返回值的演示:
var x []int // x是一个nil切片
fmt.Println(x) // 输出[]
fmt.Println(x == nil) // 输出true
x = append(x, 5) // x是一个包含一个元素5的切片
fmt.Println(x) // 输出[5]
fmt.Println(x == nil) // 输出false
在检查这些特性时容易混淆的一点是,fmt
包将nil切片和空切片都打印为相同的表示形式[]
。
英文:
The named return slice is initialized to nil. The following statement works because a nil slice is handled the same as an empty slice by the append
function.
s = append(s, 5)
Nil slices are handled the same as empty slices because the length and capacity of a nil slice are defined to be zero, the same as an empty slice.
The feature is unrelated to named return values. Here's a demonstration without return values:
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
A confusing point when examining these features is that the fmt
package prints nil slices and empty slices with the same representation, []
.
答案2
得分: 2
你可以将项目附加到nil切片中,无论它是nil还是非nil。
看下面的示例:
package main
import "log"
func main() {
a := a() // 无论它返回nil
log.Println("a是否为nil:", a == nil)
a = append(a, 1) // 你可以将项目附加到nil切片中
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 a是否为nil: true
2022/06/19 09:52:02 [1]
2022/06/19 09:52:02 [5 2]
英文:
You can append items to nil slice too, no matter it's nil or not.
Look at the example below:
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
}
And the result:
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]
答案3
得分: 1
在Go语言中,任何具名返回变量(也称为“结果参数”,根据规范的说法)都会被“预初始化”为相应类型的零值,与任何没有初始化器的局部变量完全相同:
var i int
var f float64
var s string
i
是零(整数),f
是零(0.0
,float64),s
是“零”(空字符串 ""
)。所以对于你的函数也是一样的:
func returnNamedSlice(num int) (s []int) {
// ... 在这里编写代码 ...
return
}
在函数的顶部,也就是 // 在这里编写代码
的地方,s
被初始化为“零”,即 []int(nil)
:nil
被转换为 []int
类型。这在Go规范的返回语句部分有描述。
你必须将 s
设置为某个非 nil
值,以返回一个非 nil
值。你不必使用 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
赋予了新值,这一点很重要;请参阅规范中的延迟语句示例。
英文:
Any named-return-variable ("result parameter", as the spec calls it) in Go is "pre-initialized" to the appropriate zero value, exactly the same as any locally-defined variable that has no initializer:
var i int
var f float64
var s string
i
is zero (integer), f
is zero (0.0
, float64), and s
is "zero" (empty string ""
). So it is with your function:
func returnNamedSlice(num int) (s []int) {
// ... code here ...
return
}
At the top of the function, where the // code here
code goes, s
is initialized to "zero", i.e., []int(nil)
: nil
as converted to []int
. This is described under the Return statements section of the Go spec.
You must set s
to some non-nil value to return some non-nil value. You do not have to use append
but it's pretty standard to append to the appropriately typed nil
since that makes it easy to build up a list in a loop or with a series of if
tests or whatever:
if conditionA {
s = append(s, 42)
}
if conditionB {
s = append(s, 6, 9)
}
But:
if conditionC {
s = []int{3, 1, 4, 1, 5, 9}
}
will work too.
Whatever s
is set to in the end, that's what it will hold at return time. Note that:
return someval
means (1) assign the value to s
, and then (2) return (in that order). If a deferred function then calls panic
and there's a panic handler that traps the panic and uses s
and/or assigns a new value to s
, this matters; see the Defer statement examples in the spec.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论