SoFunction
Updated on 2025-03-03

Detailed explanation of the difference between make and new in golang

Preface

This article mainly introduces relevant content to you about the difference between make and new in golang. We will share it for your reference and learning. Without further ado, let’s take a look at the detailed introduction together:

Both new and make can be used to allocate space and initialize types, but they do differ.

new(T) returns a pointer to T

new(T) allocates space for a new value of type T and initializes this space to the zero value of T. It returns the address of the new value, that is, the pointer of type T, which points to the newly allocated zero value of T.

p1 := new(int)
("p1 --> %#v \n ", p1) //(*int)(0xc42000e250) 
("p1 point to --> %#v \n ", *p1) //0
var p2 *int
i := 0
p2 = &i
("p2 --> %#v \n ", p2) //(*int)(0xc42000e278) 
("p2 point to --> %#v \n ", *p2) //0

The above code is equivalent,new(int) Initialize the allocated space to the zero value of int, that is, 0, and return the pointer of int, which is the same as directly declaring the pointer and initializing it.

make can only be used for slice, map, channel

make can only be used for three types: slice, map, channel,make(T, args)Returns a value of type T after initialization. This new value is not a zero value of type T, nor is it a pointer *T, but a reference to T after initialization.

var s1 []int
if s1 == nil {
 ("s1 is nil --> %#v \n ", s1) // []int(nil)
}
s2 := make([]int, 3)
if s2 == nil {
 ("s2 is nil --> %#v \n ", s2)
} else {
 ("s2 is not nill --> %#v \n ", s2)// []int{0, 0, 0}
}

The zero value of slice is nil. After using make, slice is an initialized slice, that is, the length, capacity, and the array pointed to at the bottom are all initialized by make. At this time, the content of slice is filled with the zero value of type int, the form is [0 0 0], and map and channel are similar.

var m1 map[int]string
if m1 == nil {
 ("m1 is nil --> %#v \n ", m1) //map[int]string(nil)
}
m2 := make(map[int]string)
if m2 == nil {
 ("m2 is nil --> %#v \n ", m2)
} else {
 ("m2 is not nill --> %#v \n ", m2) map[int]string{} 
}
var c1 chan string
if c1 == nil {
 ("c1 is nil --> %#v \n ", c1) //(chan string)(nil)
}
c2 := make(chan string)
if c2 == nil {
 ("c2 is nil --> %#v \n ", c2)
} else {
 ("c2 is not nill --> %#v \n ", c2)//(chan string)(0xc420016120)
}

make(T, args) returns a reference to T

If not specified, go functions are passed by values ​​by default, that is, the parameters passed through the function are copies of the value, and modifying the value inside the function does not affect the value itself, butmake(T, args) The returned value can be directly modified after passing the parameters through the function, that is, map, slice, channel, and modification inside the function will affect the value outside the function.

func modifySlice(s []int) {
 s[0] = 1
}
s2 := make([]int, 3)
("%#v", s2) //[]int{0, 0, 0}
modifySlice(s2)
("%#v", s2) //[]int{1, 0, 0}

This meansmake(T, args)The return is the reference type, and the original value can be changed directly inside the function, as is the case for map and channel.

func modifyMap(m map[int]string) {
 m[0] = "string"
}
func modifyChan(c chan string) {
 c <- "string"
}
m2 := make(map[int]string)
if m2 == nil {
 ("m2 is nil --> %#v \n ", m2) 
} else {
 ("m2 is not nill --> %#v \n ", m2) //map[int]string{}
}
modifyMap(m2)
("m2 is not nill --> %#v \n ", m2) // map[int]string{0:"string"}
c2 := make(chan string)
if c2 == nil {
 ("c2 is nil --> %#v \n ", c2)
} else {
 ("c2 is not nill --> %#v \n ", c2)
}
go modifyChan(c2)
("c2 is not nill --> %#v ", <-c2) //"string"

Rarely need to use new

type Foo struct {
 name string
 age int
}
var foo1 Foo
("foo1 --> %#v\n ", foo1) //{age:0, name:""}
 = 1
()
foo2 := Foo{}
("foo2 --> %#v\n ", foo2) //{age:0, name:""}
 = 2
()
foo3 := &Foo{}
("foo3 --> %#v\n ", foo3) //&{age:0, name:""}
 = 3
()
foo4 := new(Foo)
("foo4 --> %#v\n ", foo4) //&{age:0, name:""}
 = 4
()
var foo5 *Foo = new(Foo)
("foo5 --> %#v\n ", foo5) //&{age:0, name:""}
 = 5
()

foo1 and foo2 are the same types, both are values ​​of Foo type. foo1 is declared through var, Foo filed is automatically initialized to the zero value of each type, and foo2 is initialized through literals.

foo3, foo4 and foo5 are the same types, both are pointers to Foo *Foo.

But all foo can be directly used to read or modify Foo's filed, why?

If x is addressable, the filed set of &x contains m, and (&x).m is equivalent, go automatically converts, that is, the call is equivalent, go automatically converts it below.

Therefore, you can directly use struct literal to create objects, which can achieve the same situation as new creation without using new.

summary

new(T) returns the pointer *T of T and points to the zero value of T.

The initialized T returned by make(T) can only be used for slice, map, channel.

Summarize

The above is the entire content of this article. I hope the content of this article will be of some help to your study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.