在Go Lang中编写泛型函数而没有泛型

时间:2015-03-18 08:26:49

标签: generics error-handling go

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

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

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

由于我还调用了lib函数,我没有看到通过Interfaces或Reflection解决这个问题的方法。

有什么想法吗?我完全走错了轨道还是靠近目标?

4 个答案:

答案 0 :(得分:11)

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

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

答案 1 :(得分:4)

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

您必须为要支持的每种类型创建此类功能。请注意,标准库已经包含其中一些名称为MustXXX()的名称,您可以使用它们开箱即用,例如:

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

或“类似”函数抑制error,但如果仍然出现,恐慌,例如:

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

答案 2 :(得分:3)

如果你只打算对错误(坏主意)进行恐慌或者记录它们,那么只需定义一个函数来实现它并使用它。 E.g。

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的东西,因为根据我的经验,每三个错误,如果不是第二个,则需要一些额外的处理。

答案 3 :(得分:1)

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