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
The interface in Golang is similar to Java's interface, PHP 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, and some people consider it as a static duck Typing. The public method of the so-called type T fully satisfies the requirements of interface I, that is, the type T implements a set of members as defined by interface I.
At the bottom, interface is implemented as two members, one type and one value. The official also has a document: Http://golang.org/doc/go_faq.html#nil_error, if you are not accustomed to reading English, here is a wood-heavy translation: Go in the error type of the nil value 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.
$GOPATH/SRC
----Interface_test
--------Main.go
The code for MAIN.GO is as follows:
Package Mainimport ("FMT" "reflect") func main () {var val interface{} = Int64 (.) FMT. Println (reflect. TypeOf (val)) val = 50fmt. 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.
---translation from chai-Tai
Then look at the code:
Package Mainimport ("FMT") func main () {var val interface{} = nilif 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 proceeding, 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.
There are some areas to note about (*interface{}) (nil). 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. Or an example to illustrate:
Package Mainimport ("FMT") func main () {var val interface{} = (*interface{}) (nil)//val = (*int) (nil) if 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 Mainimport ("FMT") type data Struct{}func (this *data) error () string {return ""}func Test () error {var p *data = Nilreturn 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 Mainimport ("FMT", "unsafe") type data Struct{}func (this *data) error () string {return ""}func Test () error {var p *data = Nilreturn P}func main () {var e error = Test () d: = (*struct {itab uintptrdata uintptr}) (unsafe. Pointer (&e)) fmt. Println (d)}
$ cd $GOPATH/src/interface_test$ go build$./interface_test&{3078907912 0}
The right approach should be:
Package Mainimport ("FMT") type data Struct{}func (this *data) Error () string {return ' "}func bad () bool {return True}fun C Test () error {var p *data = Nilif 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")}}