Making slices, maps and channels

September 16, 2024

Making slices, maps and channels

The built-in function make takes a type T, optionally followed by a type-specific list of expressions. The core type of T must be a slice, map or channel. It returns a value of type T (not *T). The memory is initialized as described in the section on initial values.

Call             Core type    Result

make(T, n)       slice        slice of type T with length n and capacity n
make(T, n, m)    slice        slice of type T with length n and capacity m

make(T)          map          map of type T
make(T, n)       map          map of type T with initial space for approximately n elements

make(T)          channel      unbuffered channel of type T
make(T, n)       channel      buffered channel of type T, buffer size n

The only time you absolutely need to use make is when creating channels. For slices and maps, there are alternatives, though there are still times when you’ll want to use make for convenience, or even performance.

These bits of code are equivalent:

x := make([]int, 0)
y := make(map[string]string)

and

x := []int{}
y := map[string]string{}

So why bother with make for these types of variables?

Mainly, for pre-allocation.

Recall our recent discussion on efficiently appending to slices. If you know that a slice will need to hold a certain number of elements, you can pre-allocate that number of elements at the time you create the slice, rather than relying on append growing the slice, and exercising the garbage collector unduely.

x := make([]int, 0, 100) // x can grow to 100 elements, without another allocation

If you know how many elements a map is likely to contain, you can also pre-allocate enough space when creating a map. Although as we see below, the exact behavior here is much less strictly defined than it is for slices.

y := make(map[string]string, 50)

Each of the size arguments n and m must be of integer type, have a type set containing only integer types, or be an untyped constant. A constant size argument must be non-negative and representable by a value of type int; if it is an untyped constant it is given type int. If both n and m are provided and are constant, then n must be no larger than m. For slices and channels, if n is negative or larger than m at run time, a run-time panic occurs.

s := make([]int, 10, 100)       // slice with len(s) == 10, cap(s) == 100
s := make([]int, 1e3)           // slice with len(s) == cap(s) == 1000
s := make([]int, 1<<63)         // illegal: len(s) is not representable by a value of type int
s := make([]int, 10, 0)         // illegal: len(s) > cap(s)
c := make(chan int, 10)         // channel with a buffer size of 10
m := make(map[string]int, 100)  // map with initial space for approximately 100 elements

Calling make with a map type and size hint n will create a map with initial space to hold n map elements. The precise behavior is implementation-dependent.

Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Length and capacity

Length and capacity The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int. Recall that int is either a 32- or 64-bit integer. So this means that the theoretical maximum length or capacity of the various types that support len and cap depends on the CPU architecture. However, this should not matter in practice, since you’d quickly exceed the available memory, before you had a slice, array, map, or other item with 2^32 elements in it.


Constant lengths and expressions

A few of the built-in functions are very special, in that they can evaluate to constant expressions. len and cap are two such functions. But they aren’t always evaluated to constant expressions, sometimes they’re more normal-ish runtime functions. Length and capacity … The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain channel receives or (non-constant) function calls; in this case s is not evaluated.


Capacity of slices

Length and capacity … The capacity of a slice is the number of elements for which there is space allocated in the underlying array. At any time the following relationship holds: 0 <= len(s) <= cap(s) Recall that a slice is backed by a fixed-length array, which may have more elements than the slice. When this is the case, the capacity of the slice is said to be the current length of the slice, plus any unused elements in the backing array that extend beyond the final element of the slice.

Get daily content like this in your inbox!

Subscribe