Golang make() is a built-in slice function used to create a slice. The make() function takes three arguments: type, length, and capacity, and returns the slice. To create dynamically sized arrays, use the make() function. The make() function allocates a zeroed array and returns a slice that refers to that array.
Using the keyword new to initialize a struct in Golang gives the user more control over the values of the various fields inside the struct .
Slices in Go and Golang The basic difference between a slice and an array is that a slice is a reference to a contiguous segment of an array. Unlike an array, which is a value-type, slice is a reference type. A slice can be a complete array or a part of an array, indicated by the start and end index.
Go has multiple ways of memory allocation and value initialization:
&T{...}
, &someLocalVar
, new
, make
Allocation can also happen when creating composite literals.
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
The difference between new
and make
can be seen by looking at the following example:
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.
Things you can do with make
that you can't do any other way:
It's a little harder to justify new
. The main thing it makes easier is creating pointers to non-composite types.
The two functions below are equivalent. One's just a little more concise:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
make
function allocates and initializes an object of type slice, map, or chan only. Like new
, the first argument is a type. But, it can also take a second argument, the size. Unlike new, make’s return type is the same as the type of its argument, not a pointer to it. And the allocated value is initialized (not set to zero value like in new). The reason is that slice, map and chan are data structures. They need to be initialized, otherwise they won't be usable. This is the reason new() and make() need to be different.
The following examples from Effective Go make it very clear:
p *[]int = new([]int) // *p = nil, which makes p useless
v []int = make([]int, 100) // creates v structure that has pointer to an array, length field, and capacity field. So, v is immediately usable
new(T)
- Allocates memory, and sets it to the zero value for type T..
..that is 0
for int, ""
for string and nil
for referenced types (slice, map, chan)
Note that referenced types are just pointers to some underlying data structures, which won't be created by new(T)
Example: in case of slice, the underlying array won't be created, thus new([]int)
returns a pointer to nothing
make(T)
- Allocates memory for referenced data types (slice, map, chan), plus initializes their underlying data structures
Example: in case of slice, the underlying array will be created with the specified length and capacity
Bear in mind that, unlike C, an array is a primitive type in Go!
That being said:
make(T)
behaves like composite-literal syntax
new(T)
behaves like var
(when the variable is not initialized)
func main() {
fmt.Println("-- MAKE --")
a := make([]int, 0)
aPtr := &a
fmt.Println("pointer == nil :", *aPtr == nil)
fmt.Printf("pointer value: %p\n\n", *aPtr)
fmt.Println("-- COMPOSITE LITERAL --")
b := []int{}
bPtr := &b
fmt.Println("pointer == nil :", *bPtr == nil)
fmt.Printf("pointer value: %p\n\n", *bPtr)
fmt.Println("-- NEW --")
cPtr := new([]int)
fmt.Println("pointer == nil :", *cPtr == nil)
fmt.Printf("pointer value: %p\n\n", *cPtr)
fmt.Println("-- VAR (not initialized) --")
var d []int
dPtr := &d
fmt.Println("pointer == nil :", *dPtr == nil)
fmt.Printf("pointer value: %p\n", *dPtr)
}
Run the program
-- MAKE --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- COMPOSITE LITERAL --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- NEW --
pointer == nil : true
pointer value: 0x0
-- VAR (not initialized) --
pointer == nil : true
pointer value: 0x0
Further reading:
https://golang.org/doc/effective_go.html#allocation_new
https://golang.org/doc/effective_go.html#allocation_make
new(T)
: it returns a pointer to type T
a value of type *T
, it allocates and zeroes the memory. new(T)
is equivalent to &T{}
.
make(T)
: it returns an initialized value of type T
, It allocates and initializes the memory. Its used for slices, map and channels.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With