64

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, line := strings.Split("foo\thttps://bar", "\t")
bookmark[name] = link

但这是无效的。

4

3 回答 3

61

正如 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

这适用于任何数组大小,但可以说它的可读性较差,并且您必须显式声明变量。

于 2013-11-07T09:48:55.660 回答
10

如果您的函数仅通过第一次出现的分隔符来拆分字符串,您始终可以创建自己的函数:

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)
}

输出:

富吧;富

操场

于 2013-11-07T09:49:45.533 回答
9

您还可以使用匿名函数:

a, b := func() (string, string) {
    x := strings.Split("foo;bar", ";")
    return x[0], x[1]
}()

注意:不要忘记()右括号末尾的 ,}否则会出现错误:

assignment mismatch: 2 variable but 1 values

这是因为没有()a 函数(1 个值)返回的不是预期的字符串(2 个值)。

于 2019-08-23T11:26:38.533 回答