TagPointers

Pointers in Go

In this post, we are going to look at pointers in Go. Pointers appear in lower level programming languages. These features let us get closer to the hardware. We can see where the data is being stored in our memory. Slices, in fact, are pointers to arrays in Go. So when we mutate the length of a slice in Go, it reassigns itself to a different array behind the scenes.

Putting Our Nose on the Hardware.

We can use this type of behavior to our advantage with smaller data structures. Pointers in Go allow us to manipulate data without having to pass it from one place to another. As a consequence, we can use them when we are dealing with multiple threads and more complex data structures. We can also use them in functions. Let’s look at an example.

In this example, we have two functions, one that uses a pointer and one that doesn’t. Neither of these functions have return statements. Therefore, there is no effect from re-assigning the variable inside of the first function. The second function has an effect on our variable in main because we are passing a memory location rather then a value.

We can’t directly use arithmetic on pointers in Go. This is a consequence of Go having garbage collection. However, once we assign a value to a pointer it will continue to point to that value for the pointer’s lifetime. The only exception to this guarantee is in the case of nil pointers.

pointers-memoryPointing with Pointers

To fully understand pointers, we need to first understand how variables look behind the scenes. All variables are like boxes. Inside of these boxes are values. These boxes need to be stored somewhere, however, and that place is the memory. Because variables can have different types, the boxes also have different sizes.

In Go, we can create variables that contain these memory addresses. Basically, theses variables are pointing to the location where the boxes are being held. That is why, we call these variables pointers.

In Go, when we pass a variable to a function, we are copying the box with the value into that function. This means that the new copy of that box has a different location in the memory. If we use a pointer instead of just a normal parameter, we can pass the original box into the function. This is why in our pointer function above, we see the variable value change without a return statement.

Now that we have a grasp of pointers, lets take a look at a simple example.

Notice that in this example we use the * and the & signs for different reasons. The & before a variable lets us assign a pointer to the memory address of the variable. The * before a pointer lets us see what the pointer is pointing at. As we get deeper into Go and start to look at interfaces and structs, we will start to see pointers more and more. These other data types will help us understand why pointers are so powerful. 

Conclusion

In this post, we looked at pointers in Go. We went over the basic idea of pointers as references to memory and we looked at how go treats variables on the hardware side.  In our next few posts we will start to look at structs and interfaces and then continue on to Go-routines and channels.  

Arrays and Slices in Go

We’ve looked at strings, numbers, and boolean values in Go. Now, we can take a look at more complex types in Go. The two main types that we are going to look at are Arrays and Slices in Go. Slices are used more in Go than arrays but slices are an abstraction on top of arrays in Go.

Arrays in Go

In Go, an array is a sequence of elements with a specific length. Both the type of the elements and the length are part of an array’s type information in Go. If we make a default array of ints of length five; the array will contain five zeros. Arrays are mutable in Go but only the elements can be changed. The length of an array in Go is fixed after declaration. We can change these elements using the index for the array.

In the examples above, you can see that we can define arrays, change their values, and can use the short declaration operator. Note that the index of an array starts at 0 and ends at the length minus one. An array of length five doesn’t have an element at index five. We also can’t use a negative index in an array in Go. 

go_array

Slices in Go

Having fixed sized arrays might seem a little limiting but this is why we have slices in Go. A slice in Go does not include the length in its type information. This means that the slice is actually a dynamically sized piece of data. This is part of why slices are used much more in Go programs. A slice literal is the same as an array literal without the length information.

In the example above, we create an array then use two slices to reference to it. When we change one of the values of one of the slices it also changes that value in the array and the other slice. This happens because slices are references to arrays. When you create a slice in Go, you are creating an array in the memory and referencing it. The slice itself does not hold any data, it just describes an underlying array. This is true even when you create and manipulate a slice without first creating an array. 

go_slicesBecause slices are references to arrays, they also have a capacity. The capacity of a slice is the length of the underlying array. Other slices can also reference the same underlying array like in the example above. You can use the len() and the cap() functions to find the length and capacity of a slice. You can also add values to a slice using a function append(). When you append a slice above its capacity, a new array will be created in memory for the slice to reference. We can also use the make keyword to create slices.

In our example above, we use the make keyword to create two slices. We then create an array and point to it with a third slice. After that, we append three more values to this slice. We then change one of the original indexes to prove that it is no longer pointing at the original array. If you want a more technical explanation about slices then look at this google blog article: Go Slices.

Multidimensional Data

We can also make multidimensional arrays and slices in Go. A multidimensional Array or Slice is an Array of Arrays or a Slice of Slices.  You can denote these multidimensional structures using multiple brackets. Here are a few quick examples.

In our first example, we just define a two-dimensional array of zeroes.  In our second example, we build a two-dimensional slice by creating and appending two slices to our original slice.  Multidimensional arrays and slices can be extremely useful in Go. One easy way to create multidimensional arrays or slices is to use nested for loops. 

Conclusion

In this post, we talked about arrays and slices in Go. We talked about how slices are references for arrays and how arrays have a fixed length in Go. We also talked about how Go manages its memory for arrays and slices. In the end, we looked at multidimensional arrays and slices in Go. In our next few posts, we will look at maps, embedded maps and then functions in Go.

Manipulating Strings in Go

Strings are a pretty standard primitive type in most programming languages. They give the programmer the ability to output messages and store data. Today, we are going to look at strings and string manipulation in Go. We are also going to take a look at some of the print and input functions in Go.

Defining Strings in Go

Strings in Go are defined using double quotes "". You can’t use single quotes '' in Go because this is reserved for single characters or runes. A string by definition is a collection of characters surrounded by double quotes. In Go, we can do many cool things with strings such as regex, data storage, output, debugging, etc.

hello-world-go

You may have noticed that in our Hello world program from the last post we imported a library called fmt. The fmt library gives us access to I/O in Go. This library gives us access to different print functions as well as scanner functions. We can use these print functions to print out to our terminal/console. We can also use the scanner functions to take in input from the command line.

Using I/O for Input and Output

The program above allows us to take in an input and then output "Hello, Input!" to the screen. In the program, we are using two different print functions and a scanner function. We are also making use of a reference and a string variable.

The fmt.Println() function will print the string or arguments that are in the parenthesis out then automatically create a new line. We could also get this behavior by changing that function to fmt.Print("\n"). The \n character set is what is called a newline character. The backslash is the escape character and the “n” is what tells it to create a new line. The fmt.Scanln() function lets us scan the input until the user hits the enter key or creates a new line.

Formatting Strings in Go

The fmt.Printf() function stands for print format. It allows us to format the string inside of the function. You may have noticed the use of a %s pair of characters. This is telling the string that we want to format that area of the string by inputting the value of a string variable, in this case, input. There are many other two letter codes that we can use to format strings in Go.

strings-in-go

As you can see above, there are many different ways to format strings and the values being passed into those strings via the fmt.printf() function. All of the print functions in the fmt library are called variadic functions. Variadic functions in Go let the user input as many arguments into them as they want. We will talk about this more later but for now it is worth mentioning at least.

A Brief Word on References and Pointers

There is at least one more thing worth looking at from this piece of code which is the line: fmt.Scanln(&input). The reason this line is so important to look at is because we are using something called a reference in place of the normal variable input. In many low-level programming languages, we have something called a pointer and something else called a reference. The and & sign right before the input variable inside of the Scanln() function indicates that we are referencing the variable called input. The & operator finds the address of a variable and we assign the input to this variable. We will talk further about references when we get to pointers later down the line.

Conclusion

In this post, we looked at strings in Go. We also looked at how we can manipulate these strings and we looked at the basic I/O library in Go. We briefly talked about variadic functions, references and pointers as well. In our next posts, we will talk about logical operators, Loops and basic control flow in Go.