英文:
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
作为参数传入。由于 g
是 nil
,所以期望输出结果为 "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 *Goof
:err
的零值恰好是error(nil)
。
或者,如果你的函数返回一个error
,return nil
将返回你想要的结果。
更多背景知识,FAQ的答案开头如下所示:
在底层,接口由两个元素实现,一个是类型,一个是值。值被称为接口的动态值,是任意的具体值,而类型是该值的类型。对于
int
值3
,接口值包含了(int, 3)
。
只有当内部值和类型都未设置时,接口值才为
nil
,即(nil, nil)
。特别地,nil
接口将始终持有nil
类型。如果我们在接口值中存储类型为*int
的指针,无论指针的值如何,内部类型都将是*int
:(*int, nil)
。因此,即使内部指针为nil
,这样的接口值也不会是nil
。
而==
严格检查类型是否相同,而不是一个类型(*Goof
)是否实现了一个接口(error
)。查看原文了解更多信息。
如果有助于澄清,这种情况不仅发生在nil
上:在这个示例中,x
和y
变量的底层数据显然是3
,但它们具有不同的类型。当你将x
和y
放入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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论