我知道Go将来不会有泛型,并且有一些建议可以用其他结构替换它们。但是下面我的例子我被卡住了。
func P(any interface{}, err error) (interface{}) {
if err != nil {
panic("error: "+ err.Error())
}
return any
}
正如您可能猜到的那样,我试图在任何错误上失败,并希望将P()
放在任何返回两个结果的函数周围,第二个是错误。这工作正常,但any
正在丢失它的类型信息,并且只是结果中的空接口。
由于我还调用了lib函数,我没有看到通过Interfaces或Reflection解决这个问题的方法。
有什么想法吗?我完全走错了轨道还是靠近目标?
答案 0 :(得分:11)
一个解决方案是go generate
您的P()
函数,每个函数对应一个您需要使用的具体类型。
参见以下示例:
go generate
"”。这会使调用这些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")
}