This is a creation in Article, where the information may have evolved or changed.
Desc: Why the error value nil is not equal to nil
This article is used to record some of the holes I encountered in the Golang development learning process about error. Perhaps you have met, perhaps you can find the answer here. Of course, you should also associate other scenarios with the error example.
Err! = Nil
The first question is: Why is nil error not equal to nil?
<!--more-->
Consider the following code:
package mainimport ( "errors" "fmt")type Err struct { err string}func (e *Err) Error() string { return e.err}func returnErr() *Err { return nil}func main() { var err error err = returnErr() fmt.Println(err, err != nil)}
First returnErr()
returns a *err with a value of nil, and then assigns the value to ERR, so what results will the FMT print? Isn't it:
<nil> false
Wrong, it will print <nil> true
. At that time oneself also have no clue, the apprenticeship is not fine, ask the big God only then know, this is the interface interface caused. You can check the official website FAQ for details.
Simply put, interface is represented by two elements, value and type. The judgment is true only if value and type are nil at the same time interface == nil
. err = returnErr()
in this process, although value is nil, the type is *err.
How to solve this problem? In my opinion, there are only two ways to start from the root:
- Do not assign the result to an interface variable. For example, the
err = returnErr()
So that err1 := returnErr()
the interference can be avoided.
Do not let the function return a custom type, such as *err. The wrong wrapper should be filtered to error, such as:
func Err() (err error) { if e := returnErr(); e != nil { return e } return}
Err = = Nil
Why is there a err == nil
problem? This is a question I see when I look at the standard library source code, which is one of the following:
func (e *AddrError) Error() string { if e == nil { // 请注意,为什么这里会判断是否为 nil return "<nil>" } s := e.Err if e.Addr != "" { s = "address " + e.Addr + ": " + s } return s}
Why do you judge again e == nil
, at that time is very puzzling. As we all know, the method (let's say this) and the variables are stored in different regions, when we call the method with a variable of a null pointer type (for example, var e *addrerror), the method executes, and only panic when the pointer operation of the NULL pointer variable is executed.
Here is an example:
// Package main provides ...package mainimport "fmt"func main() { var e *Err e.Print() e.Printf() e.Println()}type Err struct { err string}func (e *Err) Print() { fmt.Println("e.Print run")}func (e *Err) Printf() { fmt.Println(e.err)}func (e Err) Println() { fmt.Println("e.Println run")}
1, e.Print()
is completely can execute, did not solve the pointer operation.
2, e.Printf()
when the call E.err, the understanding of pointer operation occurs, it will be panic.
3, e.Println()
because the recipient is ERR and not *err,golang internal when the function is called, it will automatically solve the pointer, it will panic.