Go Cheatsheet
Pointers
Use this Go reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Basics
A pointer holds the memory address of a value. Go has pointers but no pointer arithmetic.
var p *int // nil pointer to int x := 42 p = &x // & takes the address of x fmt.Println(*p) // * dereferences: prints 42 *p = 100 // modifies x through the pointer fmt.Println(x) // 100
Address-of and Dereference Operators
| Operator | Name | Meaning |
|---|---|---|
&v | address-of | returns a pointer to v |
*p | dereference | the value at address p |
name := "Alice" ptr := &name *ptr = "Bob" fmt.Println(name) // "Bob"
Zero Value of a Pointer
The zero value of any pointer type is nil. Dereferencing a nil pointer panics.
var p *string // nil fmt.Println(p) // <nil> fmt.Println(*p) // PANIC: runtime error: invalid memory address or nil pointer dereference // Always guard if p != nil { fmt.Println(*p) }
new()
new(T) allocates zeroed storage for a T and returns *T. Equivalent to &T{} for structs.
p := new(int) // *int pointing to 0 *p = 5 s := new(string) // *string pointing to "" // Equivalent p2 := &int(0) // not valid syntax p3 := new(int) // valid
Pointers to Structs
Auto-dereferencing: you do not need (*s).Field — Go allows s.Field through a pointer.
type Point struct{ X, Y int } p := &Point{X: 1, Y: 2} p.X = 10 // sugar for (*p).X = 10 fmt.Println(*p) // {10 2}
Pointer Receivers vs Value Receivers
type Counter struct{ n int } // Value receiver: operates on a copy func (c Counter) Value() int { return c.n } // Pointer receiver: modifies the original func (c *Counter) Increment() { c.n++ } c := Counter{} c.Increment() // Go auto-takes address: (&c).Increment() c.Value() // 1
Rule: if any method uses a pointer receiver, all methods on that type should use pointer receivers for consistency.
Pass by Value vs Pass by Pointer
Go is always pass-by-value. To mutate the caller's variable, pass a pointer.
func double(n int) { n *= 2 // only modifies the local copy } func doublePtr(n *int) { *n *= 2 // modifies the caller's variable } x := 5 double(x) // x is still 5 doublePtr(&x) // x is now 10
Pointers and Interfaces
An interface value holds a (type, value) pair. When calling a pointer-receiver method via an interface, you must pass a pointer.
type Incrementer interface{ Increment() } type Counter struct{ n int } func (c *Counter) Increment() { c.n++ } var i Incrementer = &Counter{} // OK: *Counter implements Incrementer // var i Incrementer = Counter{} // COMPILE ERROR: Counter does not implement Incrementer
Pointer to Slice / Map
Slices and maps are already reference types (they contain internal pointers). You rarely need a pointer to them.
// This is unusual and seldom needed func grow(s *[]int) { *s = append(*s, 1, 2, 3) } // Idiomatic: return the new slice func grow(s []int) []int { return append(s, 1, 2, 3) }
Pointers in Data Structures
// Linked list node type Node struct { Val int Next *Node } head := &Node{Val: 1, Next: &Node{Val: 2, Next: &Node{Val: 3}}} // Binary tree type TreeNode struct { Val int Left *TreeNode Right *TreeNode }
Optional Values with Pointers
Go has no built-in Option/Maybe. Use a pointer where nil means "absent".
type User struct { Name string NickName *string // nil if not set } nick := "gopher" u := User{Name: "Alice", NickName: &nick} if u.NickName != nil { fmt.Println(*u.NickName) }
unsafe.Pointer
unsafe.Pointer bypasses Go's type system. Use only for interoperability with C or low-level memory tricks.
import "unsafe" x := int64(42) p := unsafe.Pointer(&x) // Reinterpret as [8]byte b := (*[8]byte)(p) fmt.Println(b) // uintptr: integer large enough to hold any address // Convert: unsafe.Pointer → uintptr → arithmetic → unsafe.Pointer // Never store a uintptr; GC may move the object underneath
Pointer Gotchas
// 1. Never dereference nil var p *int *p = 5 // PANIC // 2. Returning a pointer to a local variable is SAFE in Go // (unlike C — Go allocates on the heap when it escapes) func newInt(n int) *int { x := n return &x // safe: x escapes to heap } // 3. Pointer equality a := 42 p1 := &a p2 := &a fmt.Println(p1 == p2) // true (same address) b := 42 p3 := &b fmt.Println(p1 == p3) // false (different vars, different addresses) // 4. Cannot take address of map elements m := map[string]int{"a": 1} // p := &m["a"] // COMPILE ERROR: cannot take address of map index // 5. Interface nil vs typed nil var err error // nil interface var p *MyError = nil err = p // non-nil interface wrapping nil *MyError fmt.Println(err == nil) // false! (common gotcha)