This is a creation in Article, where the information may have evolved or changed.
Golang's nil, which is conceptually null, none, nil, and Null in other languages, refers to a value of 0 or null. Nil is a pre-stated identifier, also a keyword in the usual sense. In Golang, 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. The official has a clear explanation:http://pkg.golang.org/pkg/builtin/#Type
golang" is similar to Java's interface, PHP's interface, or C + + 's pure virtual base class. An interface is a protocol that specifies a set of members. This is nothing to say, this article does not intend to the macro interface concept and interface-based paradigm programming to do the analysis. The interface of the Golang language has its uniqueness: as long as the public method of type T satisfies the requirements of interface I, the object of type T can be used where the interface I is needed. The scientific name of this practice is called Structural typing
at the bottom, interface is implemented as two members, one type and one value. The official also has a document stating: http://golang.org/doc/go_faq.html#nil_error If you are not used to reading English, here is a wood-heavy translation: nil value of error type in go and Nil .
Next, write the test code and GDB to see what the interface is. will use reflection, if you do not quite understand what Golang's reflection is, there is a sentence star translated from the official blog of an article: the rule of reflection , the original text in:laws-of-reflection.
Package main import ( "FMT" "reflect") func main () { var val interface{} = Int64 (.) FMT. Println (reflect. TypeOf (val)) val = fmt. Println (reflect. TypeOf (val))}
we already know that the variable level of the interface type is implemented as two members, one is type, and the other is data. The type is used to store the dynamic type of the variable, and data is used to store the variable's details. 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). It is easy to see this with the help of GDB:
$ cd $GOPATH/src/interface_test$ go build-gcflags "-n-l" $ gdb interface_test
Let's talk about the comparison between the value of the interface type and nil. This is a more classic question, but also a pit of Golang.
Next look at the code
Package Mainimport ( "FMT") func main () { var val interface{} = Nil if val = = nil { FMT. Println ("Val is nil") } else { fmt. Println ("Val is not nil") }}
The variable val is the interface type, and its underlying structure must be (type, data). Since nil is untyped (no type) and nil is assigned to the variable Val, Val actually stores (nil, nil). It is therefore easy to know that the equal comparison of Val and nil is true.
$ cd $GOPATH/src/interface_test$ go build$./interface_testval is Nil
Assigning any other meaningful value type to Val causes Val to hold a valid type and data. That is, the underlying structure of the variable Val is definitely not (nil, nil), so it is always false to compare it to nil.
The above discussion is done around value types. before continuing with the discussion, let's look at a special case: (*interface{}) (nil). By turning nil into a pointer of type interface, the result is simply an empty interface type pointer and it points to an invalid address. Note that there is an empty interface type pointer instead of a null pointer, and the difference between the two is quite large, and children who have studied C know what the concept of NULL pointers is.
about (*interface{}) (nil) There are some areas to be aware of. Here is just the example of (*interface{}) (nil), the same for (*int) (nil), (*byte) (nil), and so on. The above code defines the interface pointer type variable val, which points to an invalid address (0x0), so Val holds invalid data. But it is of a type (*interface{}). So the underlying structure of Val should be: (*interface{}, nil). Sometimes you see an application (*interface{}) (nil), such as var ptriface = (*interface{}) (nil), and if you then point ptriface to another type of pointer, it will not compile. Or you can assign a value like this: *ptriface = 123, then the compilation is passed, but it will still be panic at run time, because ptriface points to an invalid memory address. In fact, a variable like ptriface is declared because the user only cares about the type of pointer and ignores what value it stores.
Package Mainimport ( "FMT") func main () { var val interface{} = (*interface{}) (nil) //val = (*int) (nil) I F val = = nil { FMT. Println ("Val is nil") } else { fmt. Println ("Val is not nil")
obviously, regardless of the value of the pointer: (*interface{}, nil), such an interface value is always non-nil, even if it is nil inside the pointer.
$ cd $GOPATH/src/interface_test$ go build$./interface_testval is not nil
The most common occurrence of a variable of type interface and nil equals the value of the error interface type compared to nil. 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") }}
but unfortunately, the above code is problematic.
$ cd $GOPATH/src/interface_test$ go build$./interface_teste is not nil
We can analyze it for a moment. 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 main import ( "FMT" "unsafe") type data struct{} func (this *data) Error () string {return "} Func Test ( Error { var p *data = nil return P} Func main () { var e error = Test () D: = (*struct { itab uintptr< C8/>data uintptr }) (unsafe. Pointer (&e)) FMT. Println (d)}$ cd $GOPATH/src/interface_test$ go build$./interface_test&{3078907912 0}
the right approach should be:
Package main import ( "FMT") type Data struct{} func (this *data) Error () string {return '} func bad () bool { R Eturn true} Func Test () error { var p *data = nil if bad () { return P } return nil} func main () {
var e error = Test () if E = = nil { FMT. Println ("E is nil") } else { fmt. Println ("E is not nil") }}