Error handling function for any type in Go

huangapple go评论86阅读模式
英文:

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
}

huangapple
  • 本文由 发表于 2017年8月3日 14:29:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/45476506.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定