Athavan Kanpuli

Small thoughts about Software Engineering

Understanding the Nuances of new() and make() in Go

Posted at — Feb 22, 2024

Go has couple of memory allocation primitives: new() and make().

new(T)

new(T) is allocation primitive which allocates the memory for type T but zeros it. Unlike Java or C#, go does not do further initialization. new(T) returns a pointer *T.

import "bytes"

type User struct {
	Name string
}

func main() {
	b := new(bytes.Buffer)
	fmt.Println(b.Len())

	n, _ := b.Write([]byte("Hello hello"))
	fmt.Println(n)
	b.WriteTo(os.Stdout)

	user := new(User)
	fmt.Printf("\n%#v", user)
}

// Output:
// 0
// 11
// Hello hello
// &main.User{Name:""}

As shown in the output, the variable for buffer b is allocated with zeroed memory but the variable is still available for immediate usage to write contents.

new() is specially useful to create types like buffer or mutex whose zero values could be used without further initialization.

The expressions new(User) and &User{} are equivalent.

make(T, args)

make() is different from new() in the sense that it initializes memory for type T and it takes length and capacity as arguments.

Only channels, slices and maps can be created using make() and these types references to another underlying data structures that must be initialized at the first place in order to be useful.

For example,

s := make([]int, 10, 50)

s is a slice which references to another underlying array that is initializedwith 50 elements and s points to the first 10 elements in that array.

One can initialize a slice using new() but the resulting value is nil and is rarely useful to contain elements.

Another distinction of make(T, args) and new(T) is that make do not return a pointer but returns type T.

The following example explains the difference between make and new,

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)