Golang's knowledge about nil
1. What is nil?
As we all know, when you declare a variable but still have the value of the wood, the Golang will automatically give you a corresponding default value of 0 for the variable type. This is the corresponding 0 value for each type:
bool -> false numbers -> 0 string -> "" pointers -> nilslices -> nilmaps -> nilchannels -> nilfunctions -> nilinterfaces -> nil
One more strcut:
type Person struct { Age int Name string Friends []Person}var p Person // Person{0, "", nil}
The variable p is only declared but not assigned, so all fields of P have a corresponding value of 0.
1. In the go document, nil is a predefined identifier that represents the 0 value of a pointer, channel, function, interface, map, or slice, and is not one of the key words of Go
2. Nil can only be assigned to pointers, channel, Func, interface, map, or slice type variables (non-basic types) or it will cause panic
2. What's the use of nil?
Pointers
var p *intp == nil // true*p // panic: invalid memory address or nil pointer dereference
The pointer represents the address that points to memory, which causes panic if the pointer to nil is dereferenced.
Interface and nil (highlights)
Nil can only be assigned to variables of the pointer, channel, Func, interface, map, or slice type. If this rule is not followed, panic is raised.
At the bottom, interface is implemented as two members, one type and one value
Look, there's a clear official statement here.
At the bottom, interface is implemented as two members: a type and a value. The value is called the dynamic value of the interface, which is an arbitrary concrete value, and the type of the interface is the type of the value. For an int value of 3, an interface value is schematically inclusive (int, 3).
Only if the internal values and types are not set (nil, nil), the value of an interface is nil. In particular, a nil interface will always have a nil type. If we store a pointer of type *int in an interface value, the inner type will be int, regardless of the value of the pointer: (int, nil). Therefore, such an interface value is non-nil, even if it is nil inside the pointer.
Let's see what interface is. will use reflection, about the reflection of the article you can come down to study, but also refer to this article
Reflection article explanation
package mainimport ( "fmt" "reflect")func main() { var val interface{} = int64(58) fmt.Println(reflect.TypeOf(val)) // int64 val = 50 fmt.Println(reflect.TypeOf(val)) // int}
In the example above, the first print statement output is: Int64. This is because the data that has been shown for type Int64 is assigned to the variable Val of type interface, so the underlying structure of Val should be: (Int64, 58).
For the moment, we'll describe it in this binary way, the first member of the two-tuple is type, and the second member is data. The second PRINT statement outputs: Int. This is because the literal integer in the Golang default type is int, so this time the underlying structure of Val becomes: (int, 50).
Take a look at the following code:
Package Mainimport ("FMT" "reflect") type myerror struct {Name string}func (e *myerror) Error () string {Retu RN "A"}func main () {//nil can only be assigned to pointers, channel, Func, interface, map or slice type variables (non-basic type) Otherwise the panic Var a *myerror will be thrown Here is not the interface type = = But a value of nil for the pointer variable a FMT. Printf ("%+v\n", reflect. TypeOf (a))//*main. Myerror FMT. Printf ("% #v \ n", reflect. ValueOf (a))//A = (*main. Myerror) (nil) fmt. Printf ("%p% #v \ n", &a, a)//0xc42000c028 (*main. Myerror) (nil) I: = reflect. ValueOf (a) fmt. Println (I.isnil ())//true if a = = nil {fmt. Println ("a = = nil")//A = = nil} else {fmt. PRINTLN ("A! = nil")} FMT. Println ("A Error ():", A.error ())//a Why A is nil can also invoke the method? (The value of the pointer type is nil and the method can be called!) However, you cannot assign a value operation! below:)//A.name = "1"//panic:runtime Error:invalid memory address or nil pointer dereference var b erro R = A//Why A for nil gave B and b! = Nil??? = = error is a type interface, type = *a.myerroR data = Nil FMT. Printf ("%+v\n", reflect. TypeOf (b))//type = *main. Myerror FMT. Printf ("%+v\n", reflect. ValueOf (b))//data = = Nil if b = = nil {fmt. Println ("b = = nil")} else {fmt. PRINTLN ("B! = nil")} FMT. Println ("B Error ():", B.error ())//A}
1. First A is a variable pointer, (note that a is not interface) The variable pointer is only declared, but does not point to any address, so a = = Nil
2. The value of the pointer type is nil, can also call the method, but cannot be assigned operation, otherwise it will cause panic
3. var b error = A, at this point B is a interface, that should be satisfied with the above mentioned interface and nil relationship, that is, only if its type and data are nil only = nil! (b There are types for *main. Myerror) So finally there will be b! = Nil
3. Let's look at an example of error.
Sometimes you want to customize an error-returning function to do this, and you might write the following code:
package main import ( "fmt" ) type data struct{} func (this *data) Error() string { return "" } func test() error { var p *data = nil return p } func main() { var e error = test() if e == nil { fmt.Println("e is nil") } else { fmt.Println("e is not nil") // e is not nil } }
Analysis:
Error is an interface type, the pointer returned in the test method, p, although the data is nil, but because it is returned as a wrapper error type, that is, it is of type. So its underlying structure should be (*data, nil), obviously it is non-nil. You can print and observe the underlying structure data:
package mainimport ( "fmt" "unsafe")type data struct{}func (*data) Error() string { return "" }func test() error { var p *data = nil // (*data, nil) return p}type aa struct { itab uintptr data uintptr}func main() { var e error = test() d := (*aa)(unsafe.Pointer(&e)) dd := (*struct { itab uintptr data uintptr })(unsafe.Pointer(&e)) fmt.Println(d) // &{17636960 0} fmt.Printf("%+v\n", d) // &{itab:17644608 data:0} fmt.Printf("%#v\n", d) // &main.aa{itab:0x10d3e00, data:0x0} fmt.Printf("%#v\n", dd) // &struct { itab uintptr; data uintptr }{itab:0x10d3ca0, data:0x0}}
The right approach should be:
package Main import ("FMT") type Data struct{} func (this *data) Error () string {return "} func bad () bool {return true} Func Test () error {var p *data = Nil If bad () { Return P} return nil//Direct throw Nil} func main () {var e error = Test () if E = = Nil { Fmt. Println ("E is nil")} else {fmt. Println ("E is not nil")}}