这个满足错误接口的结构体的 nil 实例并没有显示为 nil。

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

This nil instance of a struct, that satisfies the error interface, is not showing as nil

问题

这对于某人来说应该是一个简单的问题。为什么我在这里得到的不是我期望的结果("Error is not nil")?

type Goof struct {}

func (goof *Goof) Error() string {
    return fmt.Sprintf("I'm a goof")
}

func TestError(err error) {
    if err == nil {
        fmt.Println("Error is nil")
    } else {
        fmt.Println("Error is not nil")
    }
}

func main() {
    var g *Goof // nil
    TestError(g) // 期望输出 "Error is nil"
}

这段代码中,Goof 结构体实现了 error 接口的 Error() 方法。在 TestError 函数中,如果传入的 err 参数为 nil,则输出 "Error is nil",否则输出 "Error is not nil"。

main 函数中,声明了一个指向 Goof 类型的指针变量 g,并将其赋值为 nil。然后调用 TestError 函数,并将 g 作为参数传入。由于 gnil,所以期望输出结果为 "Error is nil"。

然而,实际上输出的结果是 "Error is not nil"。这是因为在 Go 语言中,nil 指针作为接口类型的参数时,虽然它的值为 nil,但它的类型不为 nil。因此,g 虽然是 nil,但它的类型是 *Goof,而不是 nil 类型。所以在 TestError 函数中,err 参数的类型是 *Goof,而不是 nil,所以输出结果为 "Error is not nil"。

要修复这个问题,可以将 TestError 函数的参数类型改为 interface{},这样就可以正确判断 err 是否为 nil。修改后的代码如下:

func TestError(err interface{}) {
    if err == nil {
        fmt.Println("Error is nil")
    } else {
        fmt.Println("Error is not nil")
    }
}

func main() {
    var g *Goof // nil
    TestError(g) // 输出 "Error is nil"
}

这样修改后,输出结果将符合预期,即 "Error is nil"。

英文:

This should be a gimme for someone. Why do I not get what I expect ("Error is not nil") here?

http://play.golang.org/p/s8CWQxobVL

type Goof struct {}

func (goof *Goof) Error() string {
	return fmt.Sprintf("I'm a goof")
}

func TestError(err error) {
	if err == nil {
		fmt.Println("Error is nil")
	} else {
		fmt.Println("Error is not nil")
	}
}

func main() {
	var g *Goof // nil
	TestError(g) // expect "Error is nil"
}

答案1

得分: 8

这是一个关于Go语言的常见问题,简单来说,接口比较会比较类型和值,而(*Goof)(nil)error(nil)具有不同的类型。

由于if err != nil是标准用法,你希望返回一个可以与之兼容的返回值。你可以声明var err error而不是var g *Gooferr的零值恰好是error(nil)

或者,如果你的函数返回一个errorreturn nil将返回你想要的结果。

更多背景知识,FAQ的答案开头如下所示:

在底层,接口由两个元素实现,一个是类型,一个是值。值被称为接口的动态值,是任意的具体值,而类型是该值的类型。对于int3,接口值包含了(int, 3)

只有当内部值和类型都未设置时,接口值才为nil,即(nil, nil)。特别地,nil接口将始终持有nil类型。如果我们在接口值中存储类型为*int的指针,无论指针的值如何,内部类型都将是*int(*int, nil)。因此,即使内部指针为nil,这样的接口值也不会是nil

==严格检查类型是否相同,而不是一个类型(*Goof)是否实现了一个接口(error)。查看原文了解更多信息。

如果有助于澄清,这种情况不仅发生在nil上:在这个示例中,xy变量的底层数据显然是3,但它们具有不同的类型。当你将xy放入interface{}中时,它们被视为不相等:

package main

import "fmt"

type Bob int

func main() {
    var x int = 3
    var y Bob = 3
    var ix, iy interface{} = x, y
    fmt.Println(ix == iy)
}
英文:

This is, it turns out, a Frequently Asked Question about Go, and the short answer is that interface comparisons compare the type and the value, and (*Goof)(nil) and error(nil) have different types.

Since if err != nil is standard, you want a return value that'll work with it. You could declare var err error instead of var g *Goof: err's zero value is conveniently error(nil)

Or, if your func returns an error, return nil will return what you want.

For more background, here's the start of the FAQ's answer:

> Under the covers, interfaces are implemented as two elements, a type and a value. The value, called the interface's dynamic value, is an arbitrary concrete value and the type is that of the value. For the int value 3, an interface value contains, schematically, (int, 3).

> An interface value is nil only if the inner value and type are both unset, (nil, nil). In particular, a nil interface will always hold a nil type. If we store a pointer of type *int inside an interface value, the inner type will be *int regardless of the value of the pointer: (*int, nil). Such an interface value will therefore be non-nil even when the pointer inside is nil.

And == is strictly checking if the types are identical, not if a type (*Goof) implements an interface (error). Check out the original for more.

If it helps clarify, this doesn't only happen with nil: in this example, the data underlying the x and y variables is obviously 3, but they have different types. When you put x and y into interface{}s, they compare as unequal:

package main

import "fmt"

type Bob int

func main() {
	var x int = 3
	var y Bob = 3
	var ix, iy interface{} = x, y
	fmt.Println(ix == iy)
}

huangapple
  • 本文由 发表于 2015年2月20日 12:10:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/28621496.html
匿名

发表评论

匿名网友

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

确定