← Back to Go Course | Chapter 8: Pointers | Lesson 4 of 6

nil Pointers

A nil pointer is like a note that says 'this points to nothing yet' -- useful to represent 'not set', but dangerous if you try to follow it anyway.
Syntax
go
var p *type  // nil
if p != nil {
    // safe to dereference
}

The Zero Value of a Pointer

A pointer variable that's declared but never assigned an address automatically has the value nil, Go's way of representing 'points to nothing'.

Example: The Zero Value of a Pointer

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// main is where the program starts running
func main() {
	// Declare p with the zero value of its type
	var p *int
	// Print the values followed by a newline
	fmt.Println("p is nil:", p == nil)
}

Checking Before Dereferencing

Because dereferencing a nil pointer panics, code that might receive a nil pointer should check for it explicitly with an if statement before using *p.

Note: Get in the habit of nil-checking any pointer that came from a lookup, optional field, or function that could fail.

Example: Checking Before Dereferencing

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// Define the function describe
func describe(p *string) string {
	// Check whether p == nil
	if p == nil {
		// Send "no value" back to the caller
		return "no value"
	}
	// Send *p back to the caller
	return *p
}

// main is where the program starts running
func main() {
	// Declare name with the zero value of its type
	var name *string
	fmt.Println(describe(name))

	s := "Go"
	fmt.Println(describe(&s))
}

Nil Pointers in Structs

A struct field that's itself a pointer type defaults to nil when the struct is created without setting it, which is useful for representing optional data -- but it must be checked before dereferencing, just like any other pointer.

Example: Nil Pointers in Structs

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// Define a struct type named Profile
type Profile struct {
	Nickname *string
}

// main is where the program starts running
func main() {
	// Short declaration: create p and infer the type
	p := Profile{}
	// Check whether p.Nickname == nil
	if p.Nickname == nil {
		// Print the values followed by a newline
		fmt.Println("no nickname set")
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Dereferencing a pointer without first checking it for nil, causing a runtime panic in production.
  2. Comparing a nil *T stored inside an interface value to nil directly and being surprised the interface itself is not nil.
  3. Forgetting struct pointer fields default to nil, not an empty struct, and must be checked before use.
Chapter Summary
  • The zero value of any pointer type is nil, meaning it points to nothing.
  • Dereferencing a nil pointer causes an immediate runtime panic.
  • Comparing a pointer to nil with == is the standard way to check whether it's been set.
  • A non-nil interface can still wrap a nil concrete pointer -- a classic Go gotcha worth knowing about.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.