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.
CodePudding user response:
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, []
.
CodePudding user response:
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]
CodePudding user response:
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.