Reputation: 5182
In Python, one can write code like this, to assign multiple values from a list:
(a, b, c, d) = [1,2,3,4]
Is there a similar set of Go library function for slices? That is, I can do this: http://play.golang.org/p/DY1Bi5omm1
package main
func get3(s []interface{}) (
a interface{},
b interface{},
c interface{},
rest []interface{}) {
return s[0],s[1],s[2],s[4:]
}
func main() {
s := make([]interface{},5);
for i :=0 ; i < 5; i++ { s[i] = i}
a,b,c,_ := get3(s)
print(a.(int))
print(b.(int))
print(c.(int))
}
Is there a standard gophery way to do this?
And is there a way around the interface{} ugliness?
Upvotes: 2
Views: 1227
Reputation: 6848
Not like that; you would need dynamic typing or parametric polymorphism, which are not available in Go. The closest I can think about is by fiddling with reflect, like this: http://play.golang.org/p/-K4jh2nZjq
// src is supposed to be []T.
// dst are supposed to be &T, except the last one, which must be a 'rest' &[]T (or nil for discarding).
// There must not be more dst vars than elements in src.
func extract(src interface{}, dst ...interface{}) {
srcV := reflect.ValueOf(src)
// Iterate over dst vars until we run out of them.
i := 0
for i = 0; i < len(dst)-1; i++ {
reflect.Indirect(reflect.ValueOf(dst[i])).Set(srcV.Index(i))
}
// Now, the rest.
restDst := dst[i]
if restDst == nil {
return
}
restV := reflect.ValueOf(restDst)
indirectRest := reflect.Indirect(restV)
l := srcV.Len() - i
indirectRest.Set(reflect.MakeSlice(restV.Type().Elem(), 0, l))
for ; i < srcV.Len(); i++ {
itemV := srcV.Index(i)
indirectRest.Set(reflect.Append(indirectRest, itemV))
}
return
}
Which then you call like:
sl := []int{1, 2, 3, 4, 5, 6} // int or any other type
var a, b, c int
var rest []int
extract(sl, &a, &b, &c, &rest)
So the ugliness doesn't get out the function.
But note that all that happens at runtime, so it's not safe nor efficient and definitely is not idiomatic Go.
Upvotes: 2
Reputation: 2446
I don't think you can, not in an idiomatic/clean way at least. You CAN do multiple assignments, but you will have to pass individual values either directly or with a closure:
package main
import (
"fmt"
)
func valuesFromList(list[]int,startFrom int) func() int {
i:=startFrom
return func() int {
ret := list[i]
i++
return ret
}
}
func main () {
list := []int{0,1,2,3,4,5,6,7,8,9}
yield := valuesFromList(list,5)
//This works
a,b,c := yield(),yield(),yield()
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
//This also works
d,e,f := list[0],list[1],list[2]
fmt.Println(d)
fmt.Println(e)
fmt.Println(f)
//This won't work
//g,h,i:= list[7:9]
}
Upvotes: 2