go - 单值上下文中的多个值

标签 go error-handling return-value multiple-return-values

由于 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

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

最佳答案

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

如果其中一个是 error,它的存​​在是有 reason 的(这是函数 可能 失败),你应该 < em>不绕过它,因为如果你这样做了,你的后续代码可能也会惨遭失败(例如导致运行时 panic )。

但是,您可能知道代码在任何情况下都不会失败。在这些情况下,您可以提供一个 helper 函数(或方法),它将丢弃 error(如果仍然发生,则引发运行时 panic )。
如果您从代码中为函数提供输入值,并且您知道它们有效,则可能会出现这种情况。
template 就是很好的例子。和 regexp包:如果您在编译时提供了有效的模板或正则表达式,则可以确保它们始终可以在运行时被解析而不会出错。为此,template 包提供了 Must(t *Template, err error) *Template函数和 regexp 包提供 MustCompile(str string) *Regexp功能:它们不返回 error,因为它们的预期用途是保证输入有效的地方。

例子:

// "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]+\]$`)

回到你的案例

如果你可以确定Get()对于某些输入值不会产生error,你可以创建一个帮助器必须() 函数,它不会返回 error 但如果仍然发生则引发运行时 panic :

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

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

How to pass multiple return values to a variadic function?

Return map like 'ok' in Golang on normal functions

关于go - 单值上下文中的多个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28227095/

相关文章:

mysql - MySQL存储过程失败,错误代码为2013(查询过程中与MySQL服务器的连接丢失)

laravel-4 - 如何在Laravel中获取选定的单选按钮值

go - 为什么 os/exec.CombinedOutput() 没有竞争条件?

c - openssl ERR_print_errors_fp() 函数,无法将错误写入文件

java - 不兼容的类型 : void cannot be converted to string

.net - 为什么ShowDialog总是返回DialogResult.Cancel?

java - 如何从方法返回数组列表

go - bool 和 *bool 之间的区别

git - 重复 key 错误!但没有重复数据

go - 空白对界面有什么作用?