This is a creation in Article, where the information may have evolved or changed.
In Golang nil
, many people mistakenly think of NULL in programming languages such as Java, PHP, and so on. But actually Golang's niu is much more complicated, and if not, let's continue reading.
nil
For pre-declared identifiers, defined in builtin/builtin.go
,
// nil is a predeclared identifier representing the zero value for a// pointer, channel, func, interface, map, or slice type.// Type must be a pointer, channel, func, interface, map, or slice typevar nil Type // Type is here for the purposes of documentation only. It is a stand-in// for any Go type, but represents the same type for any given function// invocation.type Type int
Nil value of 0
According to the Go Language specification, any type has a value of 0 when uninitialized: The Boolean type is False, the integer is 0, the string is "", and the 0 values for pointers, functions, interface, slice, channel, and map are nil.
PS: This does not say that the struct struct's 0 value is nil, because the struct's 0 value is related to its properties
nil
There is no default type, although it is a 0 value of more than one type, you must explicitly or implicitly specify the explicit type of each nil usage.
package mainfunc main() { // 明确. _ = (*struct{})(nil) _ = []int(nil) _ = map[int]bool(nil) _ = chan string(nil) _ = (func())(nil) _ = interface{}(nil) // 隐式. var _ *struct{} = nil var _ []int = nil var _ map[int]bool = nil var _ chan string = nil var _ func() = nil var _ interface{} = nil}
If you focus on the Golang keyword students will find that there is no nil
, that nil
is not the keyword, then you can define in the code nil
, then nil
it will be hidden.
package mainimport "fmt"func main() { nil := 123 fmt.Println(nil) // 123 var _ map[string]int = nil //cannot use nil (type int) as type map[string]int in assignment}
The address and value size of the nil type
nil
The memory layout of all values of a type is always the same, in other words: Different types nil
of memory addresses are the same.
package mainimport ( "fmt")func main() { var m map[int]string var ptr *int var sl []int fmt.Printf("%p\n", m) //0x0 fmt.Printf("%p\n", ptr ) //0x0 fmt.Printf("%p\n", sl ) //0x0}
Values are generally nil
represented as exceptions in the business. The size of the nil value is always the same as the size of the value with nil
the same type as the value non-nil
. Therefore, a nil identifier that represents a different 0 value may have a different size.
package mainimport ( "fmt" "unsafe")func main() { var p *struct{} = nil fmt.Println( unsafe.Sizeof( p ) ) // 8 var s []int = nil fmt.Println( unsafe.Sizeof( s ) ) // 24 var m map[int]bool = nil fmt.Println( unsafe.Sizeof( m ) ) // 8 var c chan string = nil fmt.Println( unsafe.Sizeof( c ) ) // 8 var f func() = nil fmt.Println( unsafe.Sizeof( f ) ) // 8 var i interface{} = nil fmt.Println( unsafe.Sizeof( i ) ) // 16}
The size is dependent on the compiler and architecture. The above print results are 64-bit architecture and the official Go compiler. For a 32-bit architecture, the size of the print will be half.
For the official Go compiler, the same kind of different types of two nil values are always the same size. For example, the two nil values for two different tile types ([]int and []string] are always the same.
Nil value Comparison
1. Different types nil
are not comparable.
package mainimport ( "fmt")func main() { var m map[int]string var ptr *int fmt.Printf(m == ptr) //invalid operation: m == ptr (mismatched types map[int]string and *int)}
In Go, two values of two different comparable types can be compared only if one value can be implicitly converted to another type. Specifically, there are two cases with two different values that can be compared:
- A type of one of two values is the underlying type of another.
- A type of one of two values implements the type of another value (must be an interface type).
nil
The value comparison does not deviate from the above rule.
package mainimport ( "fmt")func main() { type IntPtr *int fmt.Println(IntPtr(nil) == (*int)(nil)) //true fmt.Println((interface{})(nil) == (*int)(nil)) //false}
2. Two values of the same type nil
may not be comparable
Because map, slice, and function types are not comparable types in Golang, they have a name that is not 不可比拟的类型
, so it nil
is also illegal to compare them.
package mainimport ( "fmt")func main() { var v1 []int = nil var v2 []int = nil fmt.Println(v1 == v2) fmt.Println((map[string]int)(nil) == (map[string]int)(nil)) fmt.Println((func())(nil) == (func())(nil))}
不可比拟的类型
The value of the missing is comparable to "pure nil".
package mainimport ( "fmt")func main() { fmt.Println((map[string]int)(nil) == nil) //true fmt.Println((func())(nil) == nil) //true}
3. Two nil
values may not be equal
If one of the two compared nil values is an interface value, and the other is not, assuming that they are comparable, the comparison result is always false. The reason is that the interface value is converted to the type of the interface value before the comparison is made. The converted interface value has a specific dynamic type, but the other interface values are not. That's why the comparison is always wrong.
package mainimport ( "fmt")func main() { fmt.Println( (interface{})(nil) == (*int)(nil) ) // false}
Problems
1. function return
func nilReturn() (string,error) { return nil,nil //cannot use nil as type string in return argument}
error
the error
type does not have an error because it is an interface type.
Nil Key of 2.map
The key for map is pointer, function, interface, slice, channel, and map, then key can be nil.
package mainimport ( "fmt")func main() { mmap := make(map[*string]int,4) a:="a" mmap[&a] = 1 mmap[nil] = 99 fmt.Println(mmap) //map[0xc042008220:1 <nil>:99]}
Summarize
Nil is more difficult to understand because we often confuse the nil value and nil type, I hope you students savor the difference.