HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoMajor

Unpack slices on assignment?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
unpackslicesassignment

Problem

Is there an elegant way in Go to do multiple assignments from arrays like in Python? Here is a Python example of what I'm trying to do (split a string and then assign the resulting array into two variables).

python:
>>> a, b = "foo;bar".split(";")


My current solution is:

x := strings.Split("foo;bar", ";")
a, b := x[0], x[1]


I'm can see this getting messy in some constructs. The practical example I'm currently facing is a bookmark file parsing and assigning to a map:

bookmark := make(map[string]string)
x := strings.Split("foo\thttps://bar", "\t")
name, link := x[0], x[1]
bookmark[name] = link


Now I have a useless variable x sitting around. I'd like to do something like:

bookmark := make(map[string]string)
name, line := strings.Split("foo\thttps://bar", "\t")
bookmark[name] = link


but that's invalid.

Solution

As Sergio Tulentsev mentioned, general packing/unpacking as is done in Python is not supported. I think the way to go there is to define your own small ad-hoc function using multiple return values:

func splitLink(s, sep string) (string, string) {
    x := strings.Split(s, sep)
    return x[0], x[1]
}


And you can then write:

name, link := splitLink("foo\thttps://bar", "\t")


But this will obviously work only when at least two substrings are being split, and silently ignore if more than two were. If this is something you use a lot, it might make your code more readable though.

--EDIT--

Another way to unpack an array is via variadic pointer arguments:

func unpack(s []string, vars... *string) {
    for i, str := range s {
        *vars[i] = str
    }
}


Which let you write:

var name, link string
unpack(strings.Split("foo\thttps://bar", "\t"), &name, &link)
bookmarks[name] = link


This will work for any array size, but it is arguably less readable, and you have to declare your variables explicitly.

Code Snippets

func splitLink(s, sep string) (string, string) {
    x := strings.Split(s, sep)
    return x[0], x[1]
}
name, link := splitLink("foo\thttps://bar", "\t")
func unpack(s []string, vars... *string) {
    for i, str := range s {
        *vars[i] = str
    }
}
var name, link string
unpack(strings.Split("foo\thttps://bar", "\t"), &name, &link)
bookmarks[name] = link

Context

Stack Overflow Q#19832189, score: 78

Revisions (0)

No revisions yet.