Pointers In go.

Pointers In go.

WHAT ARE POINTERS?

image.png

Pointers are objects e.g variables that link to the memory address of another variable. The memory address of a pointer contains the memory address to the referenced variable which often looks like this 0xc00010230. Pointers are important in programming as they help us write more efficient clean code, helping us make references to various objects from various parts of a program and increase the performance of the program.

The process of creating a pointer variable is known as Referencing while the process of extracting the data the pointer holds is known as Dereferencing the pointer.

Pointers come in handy in Go when using objects like structs, arrays, maps. e.g wanting to update an object without making effects to the existing.

PASS BY VALUE & PASS BY REFERENCE

The two ways to declare variables are to Pass-by-value and Pass-by-reference. Pass-by-value is the assignment of a value to a variable or parameter directly. i.e there data type passed does not refer to another variable. Pass-by-reference is the assignment of a value by passing the address of the variable or parameter. This can be done using pointers.

DECLARING POINTERS IN GO.

Pointers are special data types in Go. A pointer datatype is given as followed by the primitive datatype(e.g int, *string e.t.c). The syntax for declaring a pointer is as thus…

var pointerName *data_type

The specified data type of the pointer is that of the object the pointer is to refer to. An example of pointer declaration is…

var num *int

REFERENCING POINTERS IN GO.

image.png

Pointers are referenced in Go using the Ampersand (&) symbol. The syntax for referencing a pointer in Go is…

var pointer_variable = &variable_name
or
pointer_variable := &variable_name

An example of pointer referencing is…

func pointer(){
a := "This is an actual variable that a pointer will link to"
pointer_a := &a
fmt.Println(pointer_a)
fmt.Println(reflect.TypeOf(pointer_a))
}

fmt.Println(pointer_a) outputs the memory address to the variable a. fmt.Println(reflect.TypeOf(pointer_a)) outputs the data type of pointer_a which is *string.

DEREFERENCING POINTERS IN GO.

Of course, the memory address of the variable or parameter isn't that important in most cases, what is important is the value stored. To access the value stored in a pointer, we have to dereference it. Dereferencing pointers in go is done with the Asterisk(*) symbol.

func pointer() {
a := 4
pointer_a := &a
fmt.Println(*pointer_a)
}

in the example above, pointer_a which refers to the variable a is dereferenced and output to the console as seen in the line of code fmt.Println(*pointer_a) .

POINTERS AND STRUCTS

image.png A good use-case for pointers is in updating objects. Let us assume we are building a music app, we would often have to update stuff such as playlists, albums e.t.c. In the case of albums, most artists release a song or two before releasing the full album. In this case, we would want to add those songs to the album when they are out, but we won't want to re-upload those songs since they also exist on our imaginary platform and that means more memory. If the album data is saved in a struct, we can easily update the album struct each time a new song rolls out or the artiste releases a deluxe

We could take the following steps.

  • Create and initialize structs for albums.
  • Each struct contains songs in the album stored in a slice.
  • Use pointers to rename and update the contents of the album when new songs roll out.

Creating the struct album and initializing with the songs datatype...

type Album struct {
name       string
songs_list []string
}

I created a struct Album and initialized it with the album name name and a slice songs_list for the list of songs in the album.

func new_album(album_name string, number_of_songs int) Album {
var songsList = make([]string,  number_of_songs)
album_details := Album{
name:       album_name,
songs_list: songsList,
}
return album_details
}

album_details creates an instance of the album type and sets the specified slice and album names. var songsList creates the slice as initialized.

The function returns the album details album_details which is an instance of the Album struct.

func (album_details *Album) update_songs(song_name string) []string
{
album_details.songs_list = append(album_details.songs_list, song_name)
return album_details.songs_list
}

Using a pointer to the Album struct, I am able to update the contents(songs) in the album.

The function update_song is a receiver function for the Album struct. The function receives the name of the song to be added to the slice and updates the slice by appending it using append(slice_name, value) method of the slice object.

The function returns the list of songs in the album.

The full Program…

package main
import "fmt"

func main() {
x := new_album("We are all alone in this together", 12)
x.update_songs("Verdansk")
x.update_songs("Clash")
fmt.Println(x)
}

type Album struct {
name       string
songs_list []string }

func new_album(album_name string, number_of_songs int) Album {
var songsList = make([]string,  number_of_songs)
album_details := Album{
name:       album_name,
songs_list: songsList,}
return album_details
}

func (album_details *Album) update_songs(song_name string) []string {
album_details.songs_list = append(album_details.songs_list, song_name)
return album_details.songs_list
}

The Output…

{We are all alone in this together [            Verdansk Clash]}

Pointers really come in handy in Go for so many uses. Have fun!

Looking to learn Go?

Check out my Golang beginners' guide here;

Connect with me on Twitter here