make — creates and initializes slices, maps, and channels with usable internal state. new — allocates zeroed memory for any type and returns a pointer.
For slices, make sets up the backing array and internal header (pointer, length, capacity). For maps, it creates the hash table. For channels, it allocates the send/receive buffer. The result is always a ready-to-use value.
1s := make([]int, 0, 1000) // preallocate for 1000 items2m := make(map[string]bool) // empty but usable3ch := make(chan int, 50) // buffered channel
new is simpler: it allocates sizeof(T) bytes, zeroes them, and returns *T. For value types (int, bool, small structs) this works. For slices/maps/channels, the zero value is nil, which panics on use until make is called.
1p := new(int) // *int → 0, usable2s := new([]int) // *[]int → nil, NOT usable3// Must still: s = make([]int, 0)
When to use:
&T{field: value} for structs.Common mistakes:
new([]int) and calling append — nil slice panic.make([]int, 10) creates 10 zero elements, not an empty slice with cap 10.make([]int, 0, expectedSize) avoids repeated reallocation.make on a non-slice/map/channel — compile error.