Go:单值上下文中的多个值

由于Go中的error handling,我经常会得到多个值函数。 到目前为止,我pipe理这个的方式非常混乱,我正在寻找最佳实践来编写更简洁的代码。

假设我有以下function:

type Item struct { Value int Name string } func Get(value int) (Item, error) { // some code return item, nil } 

我怎样才能优雅地分配一个新的variablesitem.Value 。 在介绍error handling之前,我的函数只是返回item ,我可以简单地这样做:

 val := Get(1).Value 

现在我这样做:

 item, _ := Get(1) val := item.Value 

没有办法直接访问第一个返回的variables?

非常感谢

在多值返回函数的情况下,调用函数时不能引用结果的特定值的字段或方法。

如果其中一个是error ,那是因为某个原因 (这个函数可能会失败),所以你不应该绕过它,因为如果你这样做了,你的后续代码也可能失败(例如导致运行时恐慌)。

但是,在某些情况下,您可能会知道代码不会失败。 在这些情况下,您可以提供一个帮助函数(或方法),它将放弃error (或者如果仍然发生运行时恐慌)。
如果您从代码中为函数提供input值,并且您知道它们正常工作,则可能是这种情况。
好的例子是template和正则regexp软件包:如果你在编译时提供了一个有效的模板或者正则expression式,你可以确定它们在运行时总是可以被无错地parsing。 由于这个原因, template包提供了Must(t *Template, err error) *Template函数,而regexp包提供了MustCompile(str string) *Regexp函数:它们不返回error因为它们的用途是input保证是有效的。

例子:

 // "text" is a valid template, parsing it will not fail var t = template.Must(template.New("name").Parse("text")) // `^[az]+\[[0-9]+\]$` is a valid regexp, always compiles var validID = regexp.MustCompile(`^[az]+\[[0-9]+\]$`) 

回到你的案子

如果你可以肯定的Get()不会产生某些input值的error ,你可以创build一个帮助器Must()函数,它不会返回error但如果仍然发生,则会引发运行时恐慌:

 func Must(i Item, err error) Item { if err != nil { panic(err) } return i } 

但是,在所有情况下,只要你确定它成功了,你就不应该使用它。 用法:

 val := Must(Get(1)).Value 

替代/简化

如果将Get()调用并入您的帮助函数,甚至可以进一步简化它,我们称之为MustGet

 func MustGet(value int) Item { i, err := Get(value) if err != nil { panic(err) } return i } 

用法:

 val := MustGet(1).Value 

不,但这是一件好事,因为你应该总是处理你的错误。

有些技术可以用来推迟error handling,请参阅Rob Pike的错误 。

 ew := &errWriter{w: fd} ew.write(p0[a:b]) ew.write(p1[c:d]) ew.write(p2[e:f]) // and so on if ew.err != nil { return ew.err } 

在这个博客文章的例子中,他演示了如何创build一个errWritertypes,它将推迟error handling,直到完成调用write

不,你不能直接访问第一个值。

我想这是一个黑客将返回一个值的数组而不是“项目”和“犯错”,然后只是做item, _ := Get(1)[0]但我不会推荐这个。

这样呢?

 package main import ( "fmt" "errors" ) type Item struct { Value int Name string } var items []Item = []Item{{Value:0, Name:"zero"}, {Value:1, Name:"one"}, {Value:2, Name:"two"}} func main() { var err error v := Get(3, &err).Value if err != nil { fmt.Println(err) return } fmt.Println(v) } func Get(value int, err *error) Item { if value > (len(items) - 1) { *err = errors.New("error") return Item{} } else { return items[value] } } 

就在这里。

令人惊讶,是吧? 您可以使用简单的mutefunction从多重返回中获取特定值:

 package main import "fmt" import "strings" func µ(a ...interface{}) []interface{} { return a } type A struct { B string C func()(string) } func main() { a := A { B:strings.TrimSpace(µ(E())[1].(string)), C:µ(G())[0].(func()(string)), } fmt.Printf ("%s says %s\n", aB, aC()) } func E() (bool, string) { return false, "F" } func G() (func()(string), bool) { return func() string { return "Hello" }, true } 

https://play.golang.org/p/IwqmoKwVm-

请注意,您是如何从切片/数组中select数值,然后使用types来获取实际值。

你可以阅读更多关于这篇文章背后的科学。 感谢作者。