编写没有泛型的通用错误处理函数

Writing generic error handling function without generics

我知道 Go 将来不会有泛型,并且有一些建议用其他构造替换它们。但是在我下面的例子中,我被卡住了。

func P(any interface{}, err error) (interface{}) {
    if err != nil {
        panic("error: "+ err.Error())
    }
    return any
}

正如您可能猜到的那样,我试图在出现任何错误时都失败,并希望将 P() 放在任何返回两个结果且第二个是错误的函数周围。这工作正常,但是 any 正在丢失它的类型信息并且在结果中只是一个空接口。

因为我也在调用 lib 函数,所以我看不到使用接口或反射来解决这个问题的方法。

有什么想法吗?我是完全走错了路还是接近目标了?

一个解决方案是 go generate 您的 P() 函数,一个用于您需要使用的每种具体类型。
请参阅以下示例:

这将使调用那些 lib 函数更容易,因为生成的具体 P() 实现将使用正确的类型而不是 interface{}。

你想做什么需要泛型,但正如你已经提到的,Go 不支持泛型类型。因此,您不能创建不会丢失类型的通用函数。

您必须为要支持的每种类型创建这样的函数。请注意,标准库已经包含其中一些名称为 MustXXX() 的内容,您可以开箱即用,例如:

template.Must(t *Template, err error) *Template

或 "similar" 抑制 error 的函数,但如果仍然出现,则出现恐慌,例如:

regexp.MustCompile(str string) *Regexp(抑制 error 但如果 str 不是有效的正则表达式则出现恐慌)

如果您计划只是对错误 (坏主意) 或记录它们感到恐慌,那么只需定义一个函数来执行此操作并使用它。例如

func checkErr(err error) {
    if err != nil {
        log.Println(err)
    }
}

// ...

func foo() {
    a, err := doA()
    checkErr(err)
    b, err := doB()
    checkErr(err)
    // etc.
}

用户 twotwotwo 已经链接到 Errors are values 文章,该文章显示了有关如何减少错误处理重复性的更多示例。但我建议只写整个 if err != nil 东西,因为根据我的经验,每三次错误,如果不是第二次,都需要一些额外的处理。

随着 Go 1.18(2022 年初),类型参数将被引入该语言。

根据当前的 accepted proposal 规范,您将能够编写通用 Must 函数而不牺牲类型安全性。

它将如下所示:

package main

import (
    "fmt"
    "errors"
)

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

func main() {
    fmt.Println(Must(test1())) // 450
    fmt.Println(Must(test2())) // panics...
}

func test1() (int, error) {
    return 450, nil
}

func test2() (string, error) {
    return "", errors.New("problem")
}

Go2 游乐场:https://go2goplay.golang.org/p/SHqZc5LYeAB