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

Generics 编写没有泛型的泛型错误处理函数,generics,error-handling,go,Generics,Error Handling,Go,我知道Go将来不会有泛型,并且有一些建议用其他构造来代替它们。但下面的例子让我陷入了困境 func P(any interface{}, err error) (interface{}) { if err != nil { panic("error: "+ err.Error()) } return any } 正如您可能猜到的,我试图在任何错误上失败,并希望将p()放在任何返回两个结果而第二个结果是错误的函数周围。这工作正常,但是any正在丢失它的类型

我知道Go将来不会有泛型,并且有一些建议用其他构造来代替它们。但下面的例子让我陷入了困境

func P(any interface{}, err error) (interface{}) {
    if err != nil {
        panic("error: "+ err.Error())
    }
    return any
}
正如您可能猜到的,我试图在任何错误上失败,并希望将
p()
放在任何返回两个结果而第二个结果是错误的函数周围。这工作正常,但是
any
正在丢失它的类型信息,并且在结果中只是一个空接口

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

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

一个解决方案是使用
p()
函数,每个具体类型的函数都有一个解决方案。
请参见中的示例:

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

您想要做的事情将需要泛型,但正如您已经提到的,Go不支持泛型类型。因此,不能创建不会丢失类型的常规函数

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

或抑制
错误的“类似”函数
,但如果仍然发生错误,则会出现恐慌,例如:


(抑制
错误
,但如果
str
不是有效的regexp,则会导致恐慌)

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

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

// ...

func foo() {
    a, err := doA()
    checkErr(err)
    b, err := doB()
    checkErr(err)
    // etc.
}
用户Two已经链接到了这篇文章,其中展示了更多关于如何减少错误处理重复性的示例。但是如果出错,我建议只编写整个
nil,因为根据我的经验,每三个错误,如果不是第二个,都需要一些额外的处理。

对于Go 1.18(2022年初),类型参数将被引入到语言中

根据当前的规范,您将能够在不牺牲类型安全性的情况下编写一个通用的
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游乐场:

不要这样做。如果出错,只需编写
nil
一点一点地大量使用,这样就不那么烦人了。如果你写了一些完全重复的
err!=nil
s构成了太多的代码,您可以,或者如果某些或所有错误肯定会导致整个操作失败,在不可恢复的错误包装上写一个panic,如
mustWrite
,然后
recover
从panic中恢复,然后它才能离开您的包。我建议您停止尝试适应“language X的做事方式”进入密码。Go到处都有明确的错误处理,没有真正的异常(panic/recover与C++/Java异常的含义不同)。特别是,千万不要编写一个Go包,它会在诸如
os.Open
之类的东西上出现恐慌,返回一个
os.PathError
。即使你曾经找到一个你想在错误上恐慌的地方,只要
panic(err)
。if Unrecover上的输出几乎相同,但是
recover
将获得原始错误,而不是字符串表示。很好地更新了我2015年的答案。向上投票。