I was learning golang, and as I was going through the chapter that describes Structures, I came across different ways to initialize structures.
p1 := passport{}
var p2 passport
p3 := passport{
Photo: make([]byte, 0, 0),
Name: "Scott",
Surname: "Adam",
DateOfBirth: "Some time",
}
fmt.Printf("%s\n%s\n%s\n", p1, p2, p3)
While these print the values of the structures as
{ }
{ }
{ Scott Adam Some time}
, the following code below prints with an ampersand because it is a reference.
pointerp1 := &p3
fmt.Printf("%s", pointerp1)
pointerp2 := new(passport)
pointerp2.Name = "Anotherscott"
fmt.Printf("%s", pointerp2)
&{ Scott Adam Some time}&{ Anotherscott }
Kindly help me with my doubts.
in the usage pointerp1 := &p3
, pointerp1
is the reference variable to p3
, which holds the actual data. Similarly, what would be the actual variable that holds the data for pointerp2
?
What would be the best scenarios to use these different types of initialization?
new
allocates zeroed storage for a new item or type whatever and then returns a pointer to it. I don't think it really matters on if you use new
vs short variable declaration := type{}
it's mostly just preference
As for pointer2
, the pointer2
variable holds its own data, when you do
// initializing a zeroed 'passport in memory'
pointerp2 := new(passport)
// setting the field Name to whatever
pointerp2.Name = "Anotherscott"
new
allocates zeroed storage in memory and returns a pointer to it, so in short, new will return a pointer to whatever you're making that is why pointerp2
returns &{ Anotherscott }
You mainly want to use pointers when you're passing a variable around that you need to modify (but be careful of data races use mutexes or channels If you need to read and write to a variable from different functions)
A common method people use instead of new
is just short dec a pointer type:
blah := &passport{}
blah is now a pointer to type passport
You can see in this playground:
http://play.golang.org/p/9OuM2Kqncq
When passing a pointer, you can modify the original value. When passing a non pointer you can't modify it. That is because in go variables are passed as a copy. So in the iDontTakeAPointer
function it is receiving a copy of the tester struct then modifying the name field and then returning, which does nothing for us as it is modifying the copy and not the original.
There is variable that holds the data yet. You can dereference the pointer using *pointerp2
, and even assign it that to a variable (p2 := pointerp2
), but this variable would be a copy of the data. That is, modifying one no longer affects the other (http://play.golang.org/p/9yRYbyvG8q).
new
tends to be less popular, especially with regard to structs. A good discussion of its purpose (hint: it came first) and use cases can be found at https://softwareengineering.stackexchange.com/a/216582.
Edit: Also, p1
is not really a different kind of initialization from p3
, but instead of assigning a value to any of the type's fields they are initialized to their zero value (""
for string
, nil
for []byte
). The same would happen for any omitted fields:
p4 := passport{
Name: "Scott",
Surname: "Adam",
}
In this case, p4.Photo
and p4.DateOfBirth
would still be zero-valued (nil
and ""
respectively). The passport{}
case it just one where all the fields are omitted.
All the new keyword does is basically create a instance of the type you want. However instead of returning the plain declaration of the type, it references it and return the acutal memory address of that type in the program process heap.