In the previous post, I already talked about the zero values and nil in Golang. In today's article, we will discuss how to detect nil value in Go.nil
 is a predefined identifier in Go that represents zero values of many types. nil
is usually mistaken as null (or NULL) in other languages, but they are different.
Using nil in Golang
We can use nil
without declaring it. nil
can represent the zero values of many data types:
- pointer types (including type-unsafe ones).
- map types.
- slice types.
- function types.
- channel types.
- interface types.
Common nil detection in Golang
When storage is allocated for a variable, either through a declaration or a call of new
, or when a new value is created, either through a composite literal or a call of make
, and no explicit initialization is provided, the variable or value is given a default value. Each element of such a variable or value is set to the zero value for its type: false
 for booleans, 0
 for numeric types, ""
 for strings, and nil
 for pointers, functions, interfaces, slices, channels, and maps. This initialization is done recursively, so for instance each element of an array of structs will have its fields zeroed if no value is specified.
In the example below, we will try to convert a string to unit8 and see how we can catch the error if it is not nil
:
package main
import (
"fmt"
"strconv"
)
func main() {
s := "111a"
fmt.Printf("%v %T\n", s, s)
in, err := strconv.Atoi(s)
// catch the error if it is not nil
if err != nil {
fmt.Println(err) //strconv.Atoi: parsing "111a": invalid syntax
}
fmt.Printf("%v %T\n", in, in) // 0 int
s2 := "111"
fmt.Printf("%v %T\n", s2, s2)
in2, err := strconv.Atoi(s2)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%v %T\n", in2, in2) // 0 int
}
Output:
111a string
strconv.Atoi: parsing "111a": invalid syntax
0 int
111 string
111 int
Explanation
In the code shown below, we try to handle errors by creating an error variable which is an error
type. The zero value for the error
type is nil, so we can use the operator !=
to compare our variable to nil.
If it is not nil,
it means our program has some problems, we will print the error message and try to handle this case.
Check if a pointer is nil or not
In this example, the pointer is checked whether it is a nil pointer or not:
package main
import "fmt"
type Test struct {
}
func main() {
var ptr *Test // pointer
var intVal = 123
var ptr1 *int = &intVal
fmt.Printf("ptr is a nil pointer?: %v\n", ptr == nil)
fmt.Printf("ptr1 is a nil pointer?: %v\n", ptr1 == nil)
}
Output:
ptr is a nil pointer?: true
ptr1 is a nil pointer?: false
Check if a struct is nil or not
In this example, we will try to compare a struct instance to nil.
package main
import "fmt"
type Config struct {
Host string
Port float64
Username string
Password string
Setup bool
}
func main() {
var conf Config
if conf == nil {
fmt.Println("The config is nil!")
} else {
fmt.Println("The config is not nil")
}
}
Explanation
You are comparing a structure instance and nil, which is why the compiler prompts an error message. Since they are not the same type, so the comparison is invalid. The elements of an array or struct will have their fields zeroed if no value is specified. So there's no way to set a struct value to nil
. But you could set the value of a pointer to a struct to nil. As mentioned above, the zero value of pointer types is nil
.
package main
import "fmt"
type Config struct {
Host string
Port float64
Username string
Password string
Setup bool
}
func main() {
var conf *Config // nil
// not nil
conf2 := &Config{
Host: "www.golinuxcloud.com",
Port: 22,
Username: "testuser",
Password: "pwd",
}
if conf == nil {
fmt.Println("The config is nil!")
} else {
fmt.Println("The config is not nil")
}
if conf2 == nil {
fmt.Println("The config is nil!")
} else {
fmt.Println("The config is not nil")
}
}
Output:
The config is nil!
The config is not nil
Check if an interface is nil or not
In this example, the interface is checked whether it is a nil interface or not.
package main
import (
"fmt"
)
type TestInterface interface {
Summary() string
}
type MyString struct {
Message string
}
// Implementing methods of
func (myStr MyString) Summary() string {
return "This is a test message" + myStr.Message
}
func main() {
var interf TestInterface
fmt.Printf("interf is a nil interface: %v\n", interf == nil)
var interf2 TestInterface
interf2 = MyString{"from GoLinuxCloud"}
fmt.Printf("interf2 is a nil interface: %v\n", interf2 == nil)
}
Output:
interf is a nil interface: true
interf2 is a nil interface: false
Check if a slice is nil or not
In this example, we are going to check if a slice is nil
or not. For the slice, you must clearly understand about an empty and a nil slice. nil
and empty slices (with 0 capacity) are not the same, but their observable behavior is the same (almost all the time):
- We can call the builtin
len()
 andÂcap()
functions for both nil and empty slice - We can iterate through them with
for range
 (will be 0 iterations)
package main
import "fmt"
func main() {
var slice1 []int // nil slice
slice2 := []int{} // non-nil, empty slice
slice3 := make([]int, 0) // non-nil, empty slice
fmt.Println("slice1", len(slice1), slice1 == nil, slice1[:], slice1[:] == nil)
fmt.Println("slices2", len(slice2), slice2 == nil, slice2[:], slice2[:] == nil)
fmt.Println("slice3", len(slice3), slice3 == nil, slice3[:], slice3[:] == nil)
}
Output:
slice1 0 true [] true
slice2 0 false [] false
slice3 0 false [] false
Check if a map is nil or not
The following example shows how to check if a map is empty using the length check and check if the map is nil or not:
package main
import "fmt"
func main() {
tempMap := make(map[string]string) // empty map
var tempMap2 map[string]string // nil map
if len(tempMap) == 0 {
fmt.Println("tempMap is empty")
} else {
fmt.Println("tempMap is not empty")
}
if tempMap2 == nil {
fmt.Println("tempMap2 is nil")
} else {
fmt.Println("tempMap2 is not nil")
}
}
Output:
tempMap is empty
tempMap2 is nil
Summary
As you can see, nil
is not the zero value for every type but only for pointers, functions, interfaces, slices, channels, and maps. For nil detection, we simply use the comparator !=
. Besides that, some packages provide the IsZero()
function to check if it is nil or not. For example, the time.Time
type has the IsZero()
which reports whether the variable represents the zero time instant, January 1, year 1, 00:00:00 UTC.
References
https://go.dev/ref/spec#The_zero_value
https://go.dev/doc/tutorial/handle-errors
https://pkg.go.dev/errors