How can I get an error message in a string in Go?

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

How can I get an error message in a string in Go?

问题

我参考了这个问题,https://stackoverflow.com/questions/6012692/os-error-string-value-golang,但在我的情况下不起作用。

func (t Trans) TicketQty() (intQty int, err string) {
  defer func() {
    str := recover()
    if(str != nil){
      err = "an error"
    }
  }()
  Qty := t.TransObject["qty"].(map[string]interface{})["ticket fv"].(float64)
  intQty = 10
  return
}

err中,我需要捕获抛出的错误消息,例如,如果解析逻辑失败,它会自动抛出一个错误。这就是我需要捕获的错误。我只是举个例子 - 无论运行时异常是什么,我都需要捕获它并将其作为err传递。

我该如何实现这个?

英文:

I referred to this question, https://stackoverflow.com/questions/6012692/os-error-string-value-golang, but that is not working in my case.

func (t Trans) TicketQty() (intQty int, err string) {
  defer func() {
    str := recover()
    if(str != nil){
      err = "an error"
    }
  }()
  Qty := t.TransObject["qty"].(map[string] interface{})["ticket fv"].(float64)
  intQty = 10
  return
}

In that err, I need the error message that is thrown, e.g., if the parsing logic fails, it is throwing an error automatically. That is the error I need to catch. I am showing this only for example - whatever the runtime exception is, I need to catch it and pass as err in the return.

How can I achieve that?

答案1

得分: 147

使用errors包创建新的错误。

err = errors.New("an error")

可以通过访问err.Error()或使用fmt包的函数(例如fmt.Println(err))将返回的错误视为字符串。

除非你真的知道自己在做什么,否则不要使用recover。惯用的做法是返回所有错误,并在出现错误时处理它们。

有关更多信息,请参阅Go博客上的错误处理和Go延迟、恐慌和恢复

重新阅读你的问题,看起来你正在尝试从可能失败的类型断言中恢复。在这种情况下,建议使用“逗号,ok”习惯用法(在文档的先前链接部分提到),稍微改写一下更通用的意思是:

> “如果类型断言失败,[接收变量]仍然存在,并且是[断言的类型],但它将具有零值...”

一个简单的示例,通过类型断言测试interface{}是否实际上是float64,如果失败则生成自定义错误(而不是发生恐慌):

package main

import (
    "errors"
    "fmt"
)

// assertFloat64尝试将n断言为float64类型。
// 如果失败,则返回自定义错误。
func assertFloat64(n interface{}) error {
    // 类型断言。n是float64吗?
    f, ok := n.(float64)
    // 如果是,
    if ok {
        // 打印结果
        fmt.Printf("%f is float64\n", f)
        // 并返回nil错误。
        return nil
    }
    // 否则返回我们的自定义错误
    return errors.New(fmt.Sprintf("could not assert that \"%v\" is float64.\n", n))
}

func main() {
    // 成功
    // 1024.0 is float64
    err := assertFloat64(1024.0)
    if err != nil {
        fmt.Println(err)
    }

    // 失败
    // "foo" isn't float64
    err = assertFloat64("foo")
    if err != nil {
        fmt.Println(err)
    }
}

将打印:

1024.000000 is float64
could not assert that "foo" is float64.

Playground

英文:

Use the errors package to create new errors.

err = errors.New("an error")

The returned error can be treated as a string by either accessing err.Error(), or using the fmt package functions (for example fmt.Println(err)).

Don't use recover unless you really know what you're doing. It's idiomatic to return all errors, and to deal with them when they arise.

See Error handling and Go, and Defer, Panic and Recover on the Go blog for more info.

Rereading your question, it looks like you're trying to recover from possible failed type assertions. In this instance it's recommended to use the "comma, ok" idiom (mentioned in the previously linked section of the docs), which (slightly paraphrased to be more general) means:

> "If the type assertion fails, [the receiver variable] will still exist and be of type [whatever was asserted], but it will have the zero value..."

A simple example to test if an interface{} is actually a float64 through type assertion, and produce a custom error if it fails (instead of panicking):

package main

import (
    "errors"
    "fmt"
)

// assertFloat64 attempts a type assertion to float64.
// It returns a custom error if it fails.
func assertFloat64(n interface{}) error {
    // Type assertion. Is n float64?
    f, ok := n.(float64)
    // If yes,
    if ok {
        // print the result
        fmt.Printf("%f is float64\n", f)
        // and return nil error.
        return nil
    }
    // Else return our custom error
    return errors.New(fmt.Sprintf("could not assert that \"%v\" is float64.\n", n))
}

func main() {
    // Successful
    // 1024.0 is float64
    err := assertFloat64(1024.0)
    if err != nil {
        fmt.Println(err)
    }

    // Failure
    // "foo" isn't float64
    err = assertFloat64("foo")
    if err != nil {
        fmt.Println(err)
    }
}

Will print:

> 1024.000000 is float64
could not assert that "foo" is float64.

Playground

答案2

得分: 20

我认为这段代码可以实现你想要的功能:

func (t Trans) TicketQty() (intQty int, err error) {
  defer func() {    
    ex := recover()
    if ex != nil {     
      // "%v" 打印 ex 的值
      // 对于字符串,打印字符串本身;对于错误,打印 .Error() 方法的返回值;对于实现了 Stringer 接口的类型,打印 .String() 方法的返回值等等
      // Errorf 返回一个错误而不是字符串
      err = fmt.Errorf("%v", ex)
    }
  }()   
  ... // 做你需要的操作
  return
}

请注意,我已经将代码中的 " 替换为了 ",以使其成为有效的代码。

英文:

I think this would do what you want:

func (t Trans) TicketQty() (intQty int, err error) {
  defer func() {    
    ex := recover()
    if(ex != nil){     
      // "%v" prints the value of ex
      // for strings, it is the string, for errors .Error() method, for Stringer the .String() etc
      // Errorf returns an error instead of a string
      err = fmt.Errorf("%v", ex)
    }
  }()   
  ... // do your thing
  return
}

答案3

得分: 12

根据@intermernet的答案的补充,如果你正在使用errors.New()创建自定义错误消息,你可能想要检查创建的具体错误消息。此外,任何其他类型的错误消息也可以以相同的方式进行检查。只需使用fmt.Sprintf()函数和strings.Contains()即可。

你可以非常简单地这样做:

if fmt.Sprint(err) == "My Custom Error" {
    // 做一些操作
}

或者更好地使用strings.Contains()

if strings.Contains(fmt.Sprint(err), "Custom Error") {
    // 做一些操作
}

注意:你也可以使用err.Error(),它返回错误的字符串表示,而不是fmt.Sprint(err)

英文:

Adding to @intermernet's answer, if you are creating custom error messages using errors.New(), you might want to keep a check out for the specific error message created. Additionally any other kind of error messages too can be checked in the same manner. Just use the fmt.Sprintf() function with strings.Contains().

You can do this very simply:

if fmt.Sprint(err) == "My Custom Error" {
    // do something
}

Or better use strings.Contains():

if strings.Contains(fmt.Sprint(err), "Custom Error") {
    // do something
}

NOTE: You can also use err.Error() which returns a string representation of the error instead of fmt.Sprint(err).

huangapple
  • 本文由 发表于 2014年3月4日 19:40:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/22170942.html
匿名

发表评论

匿名网友

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

确定