New or Make

Why would I make() or new()?

Go has multiple ways of memory allocation and value initialization:

&T{...}, &someLocalVar, new, make

Allocation can also happen when creating composite literals.

new

new can be used to allocate values such as integers, &int is illegal:

new(Point)
&Point{} // OK
&Point{2, 3} // Combines allocation and initialization
new(int)
&int // Illegal
// Works, but it is less convenient to write than new(int)
var i int
&i

make

It creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T).

The reason for the distinction is that these three types represent, under the covers, references to data structures that must be initialized before use. A slice, for example, is a three-item descriptor containing a pointer to the data (inside an array), the length, and the capacity, and until those items are initialized, the slice is nil. For slices, maps, and channels, make initializes the internal data structure and prepares the value for use.

For instance,

make([]int, 10, 100)

allocates an array of 100 ints and then creates a slice structure with length 10 and a capacity of 100 pointing at the first 10 elements of the array. (When making a slice, the capacity can be omitted; see the section on slices for more information.) In contrast, new([]int) returns a pointer to a newly allocated, zeroed slice structure, that is, a pointer to a nil slice value.

new V.S. make

The difference between new and make can be seen by looking at the following examples:

Example 1:

var p *[]int = new([]int) // allocates slice structure; *p == nil; rarely useful
var v []int = make([]int, 100) // the slice v now refers to a new array of 100 ints
// Unnecessarily complex:
var p *[]int = new([]int)
*p = make([]int, 100, 100)
// Idiomatic:
v := make([]int, 100)

Example 2:

p := new(chan int) // p has type: *chan int
c := make(chan int) // c has type: chan int

Suppose Go does not have new and make, but it has the built-in function NEW. Then the example code would look like this:

p := NEW(*chan int) // * is mandatory
c := NEW(chan int)

The * would be mandatory, so:

new(int) --> NEW(*int)
new(Point) --> NEW(*Point)
new(chan int) --> NEW(*chan int)
make([]int, 10) --> NEW([]int, 10)
new(Point) // Illegal
new(int) // Illegal

Yes, merging new and make into a single built-in function is possible. However, it is probable that a single built-in function would lead to more confusion among new Go programmers than having two built-in functions.

Considering all of the above points, it appears more appropriate for new and make to remain separate.

Last updated on