英文:
Unpack slices on assignment?
问题
在Go语言中,有没有一种像Python中那样从数组中进行多重赋值的优雅方式?以下是我尝试做的一个Python示例(将一个字符串拆分并将结果数组分配给两个变量)。
python:
>>> a, b = "foo;bar".split(";")
我目前的解决方案是:
x := strings.Split("foo;bar", ";")
a, b := x[0], x[1]
我可以看到在某些情况下,这种方法可能会变得混乱。我目前面临的实际例子是解析书签文件并将其分配给一个映射:
bookmark := make(map[string]string)
x := strings.Split("foo\thttps://bar", "\t")
name, link := x[0], x[1]
bookmark[name] = link
现在我有一个无用的变量x
。我想做的是:
bookmark := make(map[string]string)
name, link := strings.Split("foo\thttps://bar", "\t")
bookmark[name] = link
但这是无效的。
英文:
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.
答案1
得分: 69
如Sergio Tulentsev所提到的,Python中的通用打包/解包操作在这里是不支持的。我认为解决这个问题的方法是定义一个自己的小型临时函数,使用多个返回值:
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
这种方法适用于任何数组大小,但可读性较差,并且你必须显式声明变量。
英文:
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.
答案2
得分: 16
你也可以使用匿名函数:
a, b := func() (string, string) {
x := strings.Split("foo;bar", ";")
return x[0], x[1]
}()
注意:不要忘记在闭合括号 `}` 的末尾加上 `()`,否则会出现错误:
```assignment mismatch: 2 variable but 1 values```
这是因为没有加上 `()`,返回的是一个函数(1个值),而不是预期的字符串(2个值)。
<details>
<summary>英文:</summary>
You could also use anonymous functions:
a, b := func() (string, string) {
x := strings.Split("foo;bar", ";")
return x[0], x[1]
}()
Note: don't forget the `()` on the end of the closing bracket `}` otherwise you will get the error:
```assignment mismatch: 2 variable but 1 values```
This is because without the `()` a function (1 value) is returned not the expected strings (2 values).
</details>
# 答案3
**得分**: 9
如果你的函数的目的是仅通过分隔符的第一个出现来拆分字符串,你可以自己编写一个函数:
```go
package main
import (
"fmt"
"strings"
)
func Split(s, sep string) (string, string) {
// 空字符串应该返回空
if len(s) == 0 {
return s, s
}
slice := strings.SplitN(s, sep, 2)
// 如果没有分隔符
if len(slice) == 1 {
return slice[0], ""
}
return slice[0], slice[1]
}
func main() {
a, b := Split("foo;bar;foo", ";")
fmt.Println(a, b)
}
输出:
foo bar;foo
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论