【问题标题】:Unpack slices on assignment?在分配时解包切片?
【发布时间】:2013-11-07 09:27:32
【问题描述】:

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

但那是无效的。

【问题讨论】:

    标签: go


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

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

      输出:

      富酒吧;富

      Playground

      【讨论】:

        【解决方案3】:

        你也可以使用匿名函数:

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

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

        assignment mismatch: 2 variable but 1 values

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

        【讨论】:

        • 这在golang中很常见吗?如果我只做一次,我应该更喜欢使用它而不是创建一个 ad-hoc 函数吗?
        • 如果像这样简单的东西你会在你的代码库中一次性使用它很好。不过取决于项目的大小和风格,如果你已经有一个专门用于临时功能的包,就不要开始放弃这些
        猜你喜欢
        • 1970-01-01
        • 2017-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-07
        • 2016-01-15
        • 2023-03-09
        • 2018-06-06
        相关资源
        最近更新 更多