Go Pointers for Padawans

Hi my friend,

like you I’m also trying to learn more about Go language. I’ve always wanted to know more about it, but as usual I always had an excuse on the tip of my tongue to postpone this desire. Now I’m done. I found a good introduction book, An Introduction to Programming in Go, and I can read Effective Go online.

I started reading about Go last week because a lot of friends are using it and they are encouraging me (pissing me off =) to do the same.

I’m a complete newbie in this technology, so if you are an advanced jedi hacker this is not for you, go play RPG with your imaginary ORCs. However, if you are just a padawan like me, try to not sleep while reading it.

If you see something wrong just leave me a comment, and I will fix it as soon as possible. Just to be clear “You suck Hobbit” is not a good comment.

Pointers: What are they?

When I used to develop software, pointers always scared a lot of programmers, mainly java programmers (calm down, just a joke =). It is really common to hear developers linking this subject to C language.

Although a lot of languages have pointers, in some languages they are more explicit or clear than others. I agree that managing pointers/memory sometimes can be a pain in the ass, but I think this is not the case of Go.

If the concept of pointers is new to you, no worries, let’s learn together. In a few words a pointer is: A variable that stores the address of other variable. Come here my little boy, just like an integer variable stores a number/integer, in the same way a pointer stores an address.

Ok, when you declare a variable in your favorite language, in fact you are just saying to the Operating System: “Hey my dear OS, I have here this variable called age and I need a place, in the memory, to store it.”. In other words, a memory address is an unique identifier that points to a place in the memory to be used to store your data. Look this simple example:

package main

func main() {
    var age int
    age = 10

    var max int
    max = 3

}

             MEMORY        ADDRESSES     VARIABLES  
        +--------------+
        |      10      |  0x20818a220      age
        +--------------+
        |              |     ...
        +--------------+
        |      3       |  0x20818a228      max
        +--------------+

Declaring pointers

This is the moment we will become men and start working with pointers. Stop crying :D! Ok, let’s declare some of them.

package main

func main() {
    // Pointer To Int
    var pi *int
    // Pointer To Bool
    var pb *bool
    // Pointer to Float
    var pf *float64
}

In GoLang a pointer is represented by an asterisk (*). In the example above we are just declaring a pointer to primitive types, such as int, bool and float. We also can create a type and then declare a pointer to our type, I will show how to do that. Hey Padawans, do you have questions or comments about declaring pointers?

Operators: * and &

Like I said before, the asterisk character (*) is used to declare a pointer. What you don’t know is, it also can be used to dereference.

It is quite simple, Dereference is when you want to access the value stored in the address. Maybe you will understand better when we show an example.

The second operator is “&” and it is used to get the variable address. All variables have an address, remember? So, when a pointer get/save a variable address it is actually pointing to the variable.

Ok, less talk and more code.

package main

import "fmt"

func main() {
    x := 10     // Declaring a int variable and assigning value 10
    var p *int  // Declaring a pointer to int

    p = &x      // Assigning to variable p the address of x

    fmt.Println(p)   // Printing the content of p
    fmt.Println(&x)  // Printing the address of x
    fmt.Println(*p)  // Dereference. Accessing the value 10
    fmt.Println(x)   // Printing the content of x

    *p = 5           // Assigning value 5 to variable x
    // p = 5         // Error: p is not a int, it is a pointer to int
    fmt.Println(*p)  // Dereference. Will print 5
    fmt.Println(x)   // Printing x variable, value = 5
}
            Variables                    Memory Addresses
                      +--------------+
              +---> x |      10      |    0x20818a220
              |       +--------------+
              |       |              |
              |       +--------------+
              +---- p | 0x20818a220  |    0x20818a228
                      +--------------+ 

Let’s understand the code above.

As you know, all variables have a memory address. In the example the x address is 0x20818a220 and the p address is 0x20818a228. The variable x is an Integer and stores the value 10. The p variable is a pointer to integer and stores the value 0x20818a220. When we do this instruction “*p = 5” we are using dereference to save the value 5 in place of 10.

I don’t know if I was clear enough. I hope so /o\. Let’s do one more example, now using a struct.

package main

import (
    "fmt"
    "reflect"
)

type Person struct {
    name string
    age int
}

func main() {
    var p *Person              // Declaring a pointer to struct Person
    fmt.Println(p)             // Printing nil

    p = &Person{"Titao", 18}   // Creating a new object Person and assigning to p
    fmt.Println(p)             // Printing p

    fmt.Println("reflect = ", reflect.TypeOf(p))
}

We are using the package reflect just to verify the type of variable p.

If you declare variables and not initialize them, golang will do it for you. Your variable will be assigned with zero value for its type. For example if your variable is an integer it will be assigned with 0, for booleans false, floats 0.0, strings “” and pointers nil.

Function parameters

I think in the golang website they explain really well about passing parameters by value.

“As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to.” (golang.org)

To understand better, let’s create a function that receives two int parameters and exchange their values. The name of this function will be swap() and it is a really common example to explain passing parameters by value.

package main

import "fmt"

// Passing parameters by value
func swap(x, y int) {
    var z int
    z = x
    x = y
    y = z
}
func main() {
    x := 2
    y := 3

    // It will not exchange the values
    swap(x, y)
    fmt.Println("X = ", x)
    fmt.Println("Y = ", y)
}

Now let’s do the same function using pointers to int.

package main

import "fmt"

// Using pointers
func swap(x, y *int) {
    var z int
    z = *x
    *x = *y
    *y = z
}

func main() {
    x := 2
    y := 3

    // It will exchange the values
    swap(&x, &y)
    fmt.Println("X = ", x)
    fmt.Println("Y = ", y)
}

I understand it can be a little bit confusing, but I found a comment from Dylan Beattie in the stack overflow that explains really well this .

“Say I want to share a web page with you. If I tell you the URL, I’m passing by reference. You can use that URL to see the same web page I can see. If that page is changed, we both see the changes. If you delete the URL, all you’re doing is destroying your reference to that page - you’re not deleting the actual page itself.

If I print out the page and give you the printout, I’m passing by value. Your page is a disconnected copy of the original. You won’t see any subsequent changes, and any changes that you make (e.g. scribbling on your printout) will not show up on the original page. If you destroy the printout, you have actually destroyed your copy of the object - but the original web page remains intact.” Ok, how is it going until now? Everybody happy? More questions?

Function New

This is the last part about pointers.

New() is a buit-in function that receives a type as argument, allocate memory enough to that type and returns a pointer to the type. In the example bellow we have a struct Person with two differente attributes: name and age. We will use the function new to allocate memory to the type Person.

The amazing part is we don’t have to realease the memory because Go has a gargabe collector:

Let’s see an example using function new.

package main

import (
    "fmt"
    "reflect"
)

type Person struct {
    name string
    age int
}

func main() {
    p := new(Person)

    p.name = "Titao"
    fmt.Println(p.name)

    fmt.Println("reflect = ", reflect.TypeOf(p))
}

There is no difference. Both will return the same, pointer to the type. Buuutttt you can use &Type{} only for struct, map, array or a slice. The new function you can use for all types.

That is it guys. You are free to drink now.

References

Like I said, I’m learning this new amazing language and I tried to share a little bit what I read in books and Internet. I hope you enjoyed reading it and let me know my mistakes.

comments powered by Disqus
Web Analytics