Difference between initialization and zeroing, and new() and make() in GoLang
new(T)
allocates zeroed storage for a new item of type T and returns its address, a value of type *T: it returns a pointer to a newly allocated zero value of type T, ready for use; it applies to value types like arrays and structs. It is
equivalent to &T{ }
make(T)
returns an initialized value of type T; it applies only to the 3 built-in
reference types: slices, maps, and channels.
var p *[]int = new([]int) // *p == nil; with len and cap 0
//or
p := new([]int)
var v []int = make([]int, 10, 50)
//or
v := make([]int, 10, 50)
//This allocates an array of 50 ints and then creates a slice v with length 10 and capacity 50 pointing
//to the first 10 elements of the array
new
returns a pointer to the type, and it's the only way to return a pointer to a native type in one step (aka int, float, complex):
intPtr := new(int)
// or
var i int
intPtr := &i
make
is for initializing channels, slices and maps.
All variables are zeroed on creation, regardless of how you create them.
The spec about make: https://golang.org/ref/spec#Making_slices_maps_and_channels
The spec about zero value: https://golang.org/ref/spec#The_zero_value
I think I have figured it and decided to share what I figured so far.
make()
vs. new()
I think I now understand the difference between make()
and new()
. At first, it was little confusing, but here what I got:
new
is simply like new
in C# or Java, but since there is no constructor in Go, all the fields (like in Java and C# terminology) will be zeroed. Zeroing means more like defaulting the fields. So if the field type is int
, then it will be 0
, or if it is a struct
, then it will be defaulted to nil
, and ""
for string
types. It is actually similar to C# and Java when there is only parameterless constructor available and you are not setting the members to something else manually.
However, types like map
, slice
, and channel
s are different. They are different because they are actually wrapper types that wrap an array type to hold the values behind the scenes. So something like List<T>
or ArrayList
in C# and Java. But using new
is not enough in this situation, because the underlying array should be initialized to an empty array to be usable. Because you cannot add or remove from a field of type array which is nil
(or null
). Therefore, they provided a make()
method to help you to initialize slices
and such.
So what happens when you use new()
over slices, for instance? Simple: Since the underlying array will be nil
, the slice will be pointing at a nil
array.
So new()
would look like the following C#/Java code:
public class Person{
public string Name;
public int Age;
public Address HomeAddress;
}
var person = new Person();
Console.WriteLine(person.Name); // ""
Console.WriteLine(person.Age); // 0
Console.WriteLine(person.HomeAddress); // null
make()
, on the other hand, would look like this for slice
,map
, and channel
s:
public class PersonList{
// We are initializing the array so that we can use it.
// Its capacity can increase.
private Person[] _personList = new Person[100];
public void Add(Person p){}
public void Remove(Person p){}
public Person Get(int index){}
}
Initialization vs. Zeroing
Simply speaking, zeroing is a form of initialization. At first, I thought they were different but they are not. Initialization is a more general term, whereas if you are set the fields (properties, etc.) of a struct or a variable to its type default such as 0
, nil
, ""
, false
, etc., then this is called zeroing. However, you can, for instance, use Composite Literals like hello := Hello{name="world"}
, which is similar to var hello = new Hello() {Name = "World"}
in C#, then you initialize your Hello
object with a name
field set to world
.
In C#, at the time you say new List<string>()
, [the underlying array field is initialized to a new array], and make)
is performing a similar operation behind the scenes but as a language construct (built in the language itself):
(http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646):
So new
does zeroing and returns a pointer back. Whereas make()
initializes to underlying array to an array with default values for each element and returns the value itself rather than a pointer.