【问题标题】:Golang returning nil does not return nilGolang 返回 nil 不返回 nil
【发布时间】:2018-12-22 02:03:35
【问题描述】:

我创建了一个自定义错误类型来包装错误,以便在 Golang 中进行调试。当有错误要打印时它可以工作,但现在它会引起恐慌。

Demo

type Error struct {
    ErrString string
}

func (e *Error) Error() string {
    return e.ErrString
}

func Wrap(err error, str string) *Error {
    if err == nil {
        return nil
    }
    e := &Error{
        ErrString: str + err.Error(),
    }
    return e
}

当我调用一个函数并且它不返回错误时,我应该仍然能够包装错误。

预期的行为是,如果错误为 nil,它应该简单地忽略它,不幸的是它会适得其反。

func foo() error {
    err := bar()
    return Wrap(err, "bar called")
}

func bar() error {
    return nil
}

func main() {
    err := foo()
    if err != nil {
        fmt.Printf("Found error %v\n",err)
        return
    }
    fmt.Println("No Errors")
}

我希望它打印No errors。相反,即使错误为零,它也会打印Found error <nil>。

【问题讨论】:

标签: go error-handling


【解决方案1】:
if err != nil

将 err 变量与 nil error 进行比较,但实际上是 nil *Error

把代码改成

err:=foo()
var  nilerror *Error = nil
if err != nilerror {
    fmt.Printf("Found error %v\n",err)
    return
}
fmt.Println("No Errors")

产生预测结果。

【讨论】:

  • 现在说得通了。我的 Wrap 函数返回 *Error nil,而不是 error nil。
  • 是否可以更改自定义错误以使其适用(如果 err != nil),而不必检查已声明的 nil 指针?
【解决方案2】:

type error

错误内置接口类型为常规接口 表示错误条件,nil 值表示否 错误。

type error interface {
    Error() string 
}

interface 类型error 的err 的值不为零。它是*main.Error 类型的值nil。其实err != nil && err.(*Error) == nil就是true


例如,

package main

import (
    "fmt"
)

func error1() {
    err := foo()
    fmt.Printf("%T %v %v %v\n", err, err, err == nil, err.(*Error) == nil)
    if err != nil {
        fmt.Printf("Found error %v\n", err)
        return
    }
    fmt.Println("No Errors")
}

func error2() {
    err := foo()
    fmt.Printf("%T %v %v %v\n", err, err, err == nil, err.(*Error) == nil)
    if err != nil && err.(*Error) != nil {
        fmt.Printf("Found error %v\n", err)
        return
    }
    fmt.Println("No Errors")
}

type Error struct {
    ErrString string
}

func (e *Error) Error() string {
    return e.ErrString
}

func Wrap(err error, str string) *Error {
    if err == nil {
        return nil
    }
    e := &Error{
        ErrString: str + err.Error(),
    }
    return e
}

func foo() error {
    err := bar()
    return Wrap(err, "bar called")
}

func bar() error {
    return nil
}

func main() {
    error1()
    fmt.Println()
    error2()
}

游乐场:https://play.golang.org/p/nwNRa2sNwj0

输出:

*main.Error <nil> false true
Found error <nil>

*main.Error <nil> false true
No Errors

【讨论】:

  • 那我该如何重写 Wrap 函数来考虑类型呢?
  • 花了一段时间,但现在我明白了。基本上就我而言,Wrap 将返回错误而不是我的自定义 Error。
  • @Ibu:没有。foo,而不是 Wrap,将返回类型 error,而不是您的自定义类型 *Error。 error 是一个接口类型。
【解决方案3】:

由于您的Error 类型实现了error 接口,因此最简单的解决方案是在Wrap() 中返回error:

func Wrap(err error, str string) error {
    if err == nil {
        return nil
    }
    e := &Error{
        ErrString: str + err.Error(),
    }
    return e
}

【讨论】:

    【解决方案4】:

    将 foo() 返回值更改为 *Error

    func foo() error {
        err := bar()
        return Wrap(err, "bar called")
    }
    

    或者:

    func Wrap(err error, str string) error{
        if err == nil {
            return nil
        }
        e := &Error{
            ErrString: str + err.Error(),
        }
        return e
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-21
      • 1970-01-01
      • 2013-02-18
      • 2019-06-20
      • 2017-12-16
      • 2014-09-27
      • 2017-06-11
      • 2014-12-29
      相关资源
      最近更新 更多