make(T, ...) — creates and initializes slices, maps, and channels, returning a usable (non-nil) value. new(T) — allocates zeroed memory for any type and returns a pointer to it.
For slices, make([]int, 5, 10) creates a slice with 5 zero-valued elements and capacity 10. For maps and channels, it allocates the necessary internal structures. The key point is that make produces a value ready for immediate use.
1s := make([]int, 0, 100) // preallocated for 100 elements2for i := 0; i < 100; i++ {3 s = append(s, i) // no reallocation4}56m := make(map[string]int, 10) // hint for ~10 entries7ch := make(chan int) // unbuffered channel
new is more primitive. It returns a pointer to zeroed memory. For simple types this works, but for slices/maps/channels the zero value is nil — you must still call make to make them functional.
1p := new(int) // *int → 02s := new([]int) // *[]int → nil (unusable until make)3*s = make([]int, 0, 10)
When to use:
&T{...} for struct initialization.Common mistakes:
new([]int) and trying to append — nil slice panic.make([]int, 10) (len=10, full of zeros) with make([]int, 0, 10) (len=0, cap=10).make results to functions that modify them — make returns a value, not a reference.