英文:
Error handling function for any type in Go
问题
我正在尝试抽象出一种经常出现的模式,但我唯一能想到的方法是通过一个通用函数来实现:
func DoStuff() MyType {
result, err := SomeProcess() // 返回 MyType
if err != nil {
log.Fatal(err)
}
return result // 或者对其进行其他操作
}
这是我的解决方案:
func FailOnError(value interface{}, err error) interface{} {
if err != nil {
log.Fatal(err)
}
return value
}
func DoStuff() MyType {
return FailOnError(SomeProcess())
}
问题是我没有编译时类型安全性,如果我想进一步处理结果,我需要显式地进行类型转换,例如:
type MyType struct {
value int
}
// 假设有这样一个函数签名
func GetItem() (MyType, error)
func Add() MyType {
item := MyType(FailOnError(GetItem()))
}
这样做还可以,但相当不优雅。而且,这意味着需要手动强制类型,这总是有些脆弱并且可能会影响性能。
有没有更好或更符合惯例的方法呢?
**编辑:**由于这似乎是一个不受欢迎的问题,那么我用以下示例来代替:
func Identity(x interface{}) interface{} {
return x
}
使用时需要:
x = int(Identity(1))
y = MyType(Identity(MyType{value}))
而且我可以这样做:
x = int(Identity(MyType{value}))
Identity
故意很简单,但不一定非得如此。它可以是一个用于记录日志或改变对象并返回的方法。我还有另一种情况,我想在一些在各种外部库中定义的类型上进行一些操作-它们足够相似,我可以编写一个函数来处理它们,但它们并不共享一个接口。
英文:
I am trying to abstract the following pattern that seems to occur quite a lot, but the only way I can think of doing so is through a generic function:
func DoStuff () MyType {
result, err := SomeProcess() // returns MyType
if err != nil {
log.Fatal(err)
}
return result // or do something else with it
}
Here's my solution:
func FailOnError(value interface{}, err error) interface{} {
if err != nil {
log.Fatal(err)
}
return value
}
func DoStuff () MyType {
return FailOnError(SomeProcess())
}
The problem is that I don't have compile-time type safety, and if I want to do anything further with the result I need to explicitly type cast it, e.g.
type MyType struct {
value int
}
// Assuming a function with this signature
func GetItem() (MyType, error)
func Add () MyType {
item := MyType(FailOnError(GetItem()))
}
This is ok, I guess, but rather inelegant. Also, it means manually enforcing types which is always somewhat fragile and a potential performance hit.
Is there a better, or more idiomatic way of doing this?
Edit: Since this seems to be a hated question, how about I use the following example instead:
func Identity(x interface{}) interface{} {
return x
}
Usage would need to be:
x = int(Identity(1))
y = MyType(Identity(MyType{value}))
And there is nothing stopping me from doing
x = int(Identity(MyType{value}))
Identity
is intentionally trivial, but need not necessarily be so. I could be, for example, and method designed to do some logging, or mutate an object and return it. Another situations I have is where I want to do some work on some types defined in various external libraries - they are similar enough that I can write a single function to handle all of them, but they don't share an interface.
答案1
得分: 1
有没有更好的、更习惯的方法来做这个?
是的:处理错误。Log.Fatal 不是错误处理。如果致命错误确实是正确的事情:只封装致命错误。
将错误致命化作为一个函数,而不是在调用处,并且请远离 interface{}
:
func abortOnError(err error) {
if err == nil {return}
log.Fatal(err)
}
func whatever() int {
x, err := someOp()
abortOnError(err)
return x+2
}
英文:
> Is there a better, or more idiomatic way of doing this?
Yes: Handle the error. Log.Fatal is not error handling. If fataling is really the right thing: Encapsulate fataling only.
Make fataling on error a function, not the calling and please stay away from interface{}
:
func abortOnError(err error) {
if err == nil {return}
log.Fatal(err)
}
func whatever() int {
x, err := someOp()
abortOnError(err)
return x+2
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论