单值上下文中的多个值

新手上路,请多包涵

由于 Go 中的错误处理,我经常以多个值函数结束。到目前为止,我管理它的方式非常混乱,我正在寻找最佳实践来编写更清晰的代码。

假设我有以下功能:

 type Item struct {
   Value int
   Name string
}

func Get(value int) (Item, error) {
  // some code

  return item, nil
}

如何优雅地将新变量分配给 item.Value 。在介绍错误处理之前,我的函数刚刚返回 item 我可以简单地这样做:

 val := Get(1).Value

现在我这样做:

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

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

原文由 Spearfisher 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 811
2 个回答

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

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

但是,在某些情况下,您 知道 代码在任何情况下都不会失败。在这些情况下,您可以提供一个 辅助 函数(或方法),它将丢弃 error (如果它仍然发生,则引发运行时恐慌)。

如果您从代码中为函数提供输入值,并且您知道它们有效,则可能会出现这种情况。

很好的例子是 templateregexp 包:如果您在编译时提供有效的模板或正则表达式,您可以确保它们始终可以在运行时无错误地解析。 For this reason the template package provides the Must(t *Template, err error) *Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don’t return error s 因为它们的预期用途是保证输入有效的地方。

例子:

 // "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))

// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)

回到你的案例

IF you can be certain Get() will not produce error for certain input values, you can create a helper Must() function which would not return the error 但如果它仍然发生,则引发运行时恐慌:

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

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

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

Go 1.18 泛型更新: Go 1.18 添加了泛型支持,现在可以编写泛型 Must() 函数:

 func Must[T any](v T, err error) T {
    if err != nil {
        panic(err)
    }
    return v
}

这在 github.com/icza/gog 中可用,作为 gog.Must() (披露:我是作者)。

替代/简化

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

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

用法:

 val := MustGet(1).Value

查看一些有趣/相关的问题:

如何将多个返回值传递给可变参数函数?

在 Golang 中以正常函数返回类似“ok”的映射

原文由 icza 发布,翻译遵循 CC BY-SA 4.0 许可协议

就在这里。

令人惊讶吧?您可以使用简单的 mute 函数从多次返回中获取特定值:

 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", a.B, a.C())
}

func E() (bool, string) {
    return false, "F"
}

func G() (func()(string), bool) {
    return func() string { return "Hello" }, true
}

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

请注意如何像从切片/数组中选择值编号,然后选择类型以获取实际值。

您可以从 这篇文章 中了解更多关于其背后的科学知识。感谢作者。

原文由 Kesarion 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题