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.
Slice assignment is a little-used, beautiful Python feature to replace a slice with another sequence. Simply select the slice you want to replace on the left and the values to replace it on the right side of the equation.
Method : Using format() + * operator + values() The * operator is used to unpack and assign. The values are extracted using values().
One of the most common use-cases of unpacking in Python is what we can call parallel assignment. Parallel assignment allows you to assign the values in an iterable to a tuple (or list ) of variables in a single and elegant statement.
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.
If your function is meant to split a string only by the first occurrence of the separator, you can always make your own function:
package main import ( "fmt" "strings" ) func Split(s, sep string) (string, string) { // Empty string should just return empty if len(s) == 0 { return s, s } slice := strings.SplitN(s, sep, 2) // Incase no separator was present if len(slice) == 1 { return slice[0], "" } return slice[0], slice[1] } func main() { a, b := Split("foo;bar;foo", ";") fmt.Println(a, b) }
Output:
foo bar;foo
Playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With