What is the difference between new() and make()?

4 minbeginnergonewmakefundamentals

Quick Answer

new(T) allocates zeroed memory for a value of type T and returns a pointer to it (*T) — it works for any type, but you almost never need it directly since &T{} does the same thing more idiomatically. make(T, args...) only works on slices, maps, and channels, and it returns an initialized (not zeroed-pointer) value of type T itself, not a pointer — because these three types need internal setup (like allocating a backing array for a slice, or setting up the channel's internal buffer) before they're usable. new([]int) gives you a pointer to a nil slice, which is rarely what you want; make([]int, 5) gives you a ready-to-use slice of length 5.

Detailed Answer

These two built-ins solve related but distinct problems, and mixing them up is a common beginner mistake.

new(T): a pointer to a zero value

p := new(int)      // p is *int, pointing to a 0
fmt.Println(*p)    // 0

type Point struct{ X, Y int }
pt := new(Point)   // pt is *Point, pointing to {0, 0}

new(T) is rarely used directly in idiomatic Go, since &Point{} or &Point{X: 1} reads more naturally and does the same thing for structs.

make(T, ...): initialized slices, maps, channels

s := make([]int, 5)          // slice of length 5, all zeros, ready to index
m := make(map[string]int)    // empty, writable map
ch := make(chan int, 10)     // buffered channel with capacity 10

Why slices/maps/channels need make, not new

var s *[]int = new([]int)  // *s is a nil slice — usable for reads, panics/breaks on writes to map-like ops
(*s) = append(*s, 1)       // this actually works, since append handles nil slices

var m *map[string]int = new(map[string]int)  // *m is a nil map
(*m)["x"] = 1              // panic: assignment to entry in nil map

A slice, map, or channel has internal state (a backing array pointer, a hash table, a buffer) that new's simple zeroing can't set up. make runs the actual initialization logic these types need, and hands back a ready-to-use value, not a pointer to one.

Quick rule of thumb

Use make for slices, maps, and channels. Use struct literals (&T{}) for everything else that needs a pointer. You'll rarely reach for new directly in real Go code.