Sebastian Gomez
Variables, Data and Structures in Go
In this post we'll walk together through the foundations of Go: variables, data types and structures. They are the base everything else is built on, so it's worth understanding them well from the start. Let's begin.
Variables
Variables in Go are containers for storing data. A variable holds a value, which can be anything from a number to a string of text or an object. When we define a variable, we specify the variable's name, the data type it belongs to and the value assigned to it. Once defined, we can use its name to refer to it and to access its value.
There are two main kinds of variables in Go: local variables and global variables. Local variables are defined inside a function and are only available within that function. Global variables are defined outside any function and are available throughout the program.
Local variables
Local variables are those defined inside a function or block of code. For example, in the following code the variable a is a local variable and only exists inside main:
package main
import "fmt"
func main() {
var a = 5
fmt.Println(a)
}
// This would be a compile error: 'a' is not defined outside the function.
// Also, a Go program cannot have loose statements at package level;
// fmt.Println(a) out here is invalid on two counts.Global variables
Global variables are variables defined outside any function or block of code. For example, in the following code the variable b is a global variable and is available throughout the file:
package main
import "fmt"
// A global variable
var b = 10
func main() {
// The variable b is available here
fmt.Println(b)
}
// It's also defined here
func otra() {
fmt.Println(b)
}Variables can also be defined as constants. Constants are values that have a fixed value and cannot be changed during the execution of the program.
Constants
Constants are values that a program cannot change during its execution. For example, in the following code PI is a constant:
const PI = 3.14159
// This will cause an error: a constant cannot be reassigned.
PI = 88Ways to initialize variables
Variables are containers for storing values during the execution of a program. For example, in the following code the variable x is first initialized along with its type as empty, and then we assign its value.
// Declaration of the variable 'x' in Go, empty
var x int
// Assignment of the integer value 5 to the variable 'x'
x = 5But it's also possible to declare it without the type, as long as we set its value. This is known as type inference. The two forms below are equivalent alternatives, they cannot be written together because redeclaring y in the same block would be a compile error:
// Type inference: we declare 'y' without expressing the type
var y = 10// Equivalent form, although here expressing the type is unnecessary
var y int = 10Assigning one variable to another
It's possible to assign the contents of one variable to another variable. This is known as pass by value or copy.
package main
import "fmt"
func main() {
// Declaration of the variable 'x' in Go
var x int
// Assignment of the integer value 5 to the variable 'x'
x = 5
fmt.Println("Value of x: ", x)
var obj = x
fmt.Println("Value of obj: ", obj)
x = 99
// The value of obj will still be 5 even though the value of x changed to 99
fmt.Println("Value of obj: ", obj)
}Data types in detail
Data types in Go determine the kind of values that can be stored and manipulated within a program. Go has a variety of primitive data types, including integers, floats, strings and booleans, as well as composite data types like arrays, slices, structs and pointers. You can also define your own data types using the type keyword.
Integers
Integers are used to store whole numeric values, like 3, -2 and 0. There are several integer types, including int8, int16, int32, int64, uint8, uint16, uint32 and uint64. There are also int and uint, whose size depends on the platform (32 or 64 bits), and which are usually the default choice when you don't need a specific size.
Floats
Floating point values are used to store numeric values with decimals, like 3.14, -2.5 and 0.0. There are two floating point types: float32 and float64.
Strings
Strings are used to store sequences of characters, like "hello world". A string is a sequence of characters encoded in UTF-8.
Booleans
Booleans are used to store logical values, like true or false.
Arrays and Slices
Here's an important distinction worth getting clear from the start. An array in Go has a fixed size set at compile time: once created, you cannot add or remove elements. A slice, on the other hand, is a flexible view over the elements and can grow using append.
An array is declared by stating its length inside brackets:
// An array of 5 elements: its size is fixed
var numeros = [5]float64{5, 10, 9, 8, 7}A slice is declared with empty brackets and can grow:
// A slice: empty brackets, its size can change
var numeros = []float64{5, 10, 9, 8, 7}
// We add an element to our slice
numeros = append(numeros, 18)In short: if you need a fixed size collection, use an array; if you need it to grow, use a slice. In practice, slices are far more common in everyday code.
Structs
Structs are used to store a set of related variables, like the name and the price of a product, in the same place. Structs are similar to arrays, but they can hold different data types.
For example, a struct that represents a product could look like this:
type Producto struct {
Nombre string
Precio float64
}And it could be used like this:
var producto Producto
producto.Nombre = "Producto 1"
producto.Precio = 100In short, Go offers a wide variety of data types and structures to fit the needs of your program. Knowing them and using them properly will let you write more efficient and better organized programs.
A note about quotes
In Go, double and single quotes have specific and distinct uses.
Double quotes (" "): used to represent strings of text. A string in Go is an immutable sequence of bytes and can contain any data that bytes can represent. For example, "Hola Mundo" is a string. Strings delimited by double quotes can contain escaped special characters, like \n (newline) or \t (tab).
Single quotes (' '): used to represent a single character, known as a rune in Go. A rune is a data type that represents a Unicode code point. For example, 'A' is a rune that represents the letter A. Unlike strings, a rune is an integer value and occupies 4 bytes (32 bits) in Go.
Ten examples with their solutions
Calculate the sum of two numbers:
package main
import "fmt"
func main() {
fmt.Println("Calculate the sum of two numbers:")
var a = 5
var b = 10
var resultado = sumar(a, b)
fmt.Println("The result is: ", resultado)
}
func sumar(a int, b int) int {
var sum = a + b
return sum
}Calculate the product of two numbers:
package main
import "fmt"
func main() {
fmt.Println("Calculate the product of two numbers:")
var a = 5.0
var b = 10.1
var resultado = producto(a, b)
fmt.Println("The result is: ", resultado)
}
// When using floating point numbers, the float64 type is assigned automatically
func producto(a float64, b float64) float64 {
var sum = a * b
return sum
}Calculate the average of a list of numbers:
package main
import "fmt"
func main() {
fmt.Println("Calculate the average of a list of numbers:")
// This is a slice of numbers, that is, a collection of numbers that can grow
var numeros = []float64{5, 10, 9, 8, 7}
var resultado = promedio(numeros)
fmt.Println("The result is: ", resultado)
}
func promedio(numeros []float64) float64 {
var sum = 0.0
for _, numero := range numeros {
sum += numero
}
return sum / float64(len(numeros))
}Calculate the factorial of a number:
func factorial(n int) int {
if n == 0 {
return 1
}
return n * factorial(n-1)
}Calculate the area of a circle:
import "math"
func areaCirculo(radio float64) float64 {
return math.Pi * radio * radio
}Calculate the perimeter of a square:
func perimetroCuadrado(lado float64) float64 {
return lado * 4
}Calculate the volume of a sphere:
import "math"
func volumenEsfera(radio float64) float64 {
// We use 4.0 / 3.0 to force floating point division.
// With 4 / 3 (integers) the result would be 1 and the volume would be wrong.
return (4.0 / 3.0) * math.Pi * radio * radio * radio
}Calculate the area of a triangle:
func areaTriangulo(base float64, altura float64) float64 {
return base * altura / 2
}Calculate the hypotenuse of a right triangle:
import "math"
func hipotenusa(cateto1 float64, cateto2 float64) float64 {
return math.Sqrt(cateto1*cateto1 + cateto2*cateto2)
}Ask the user for two numbers and print the result on screen:
package main
import "fmt"
func ingresoDatos() {
var a, b float64
fmt.Println("Enter number 1: ")
fmt.Scanln(&a)
fmt.Println("Enter number 2: ")
fmt.Scanln(&b)
fmt.Println("The numbers you entered are: ", a, b)
}Suggested exercises
Below I leave you 20 more exercises so you can practice and send the solution as a Pull request to this repository: github.com/seagomezar/goparaprincipiantes.
Note: verify that the repository link is still live before publishing.
- Print the length of a string.
- Compare two integers and show the larger one.
- Calculate the square of a number.
- Create a function to convert a string to uppercase.
- Create a function to convert a string to lowercase.
- Determine whether a string contains a given substring.
- Determine whether a number is even or odd.
- Determine whether a string is a palindrome.
- Increment a number by one.
- Determine whether a number is within a given range.
- Get the index of the first occurrence of a substring in a string.
- Get the sum of two integers.
- Check whether a number is divisible by another.
- Determine whether a string is a number.
- Calculate the greatest common divisor (GCD) of two numbers.
- Determine whether a string starts with a given substring.
- Get the size of an array.
- Get the number of unique elements in a slice.
- Determine whether a number is prime.
- Get the indices of the duplicate elements in a slice.
3-point summary
- Variables hold values and can be local (inside a function) or global (available throughout the program); with
varyou can declare them with an explicit type or let Go infer it. - Go has primitive types (integers, floats, strings, booleans) and composite ones (fixed size arrays, slices that grow with
append, structs and pointers). - Mind the language details: constants cannot be reassigned, copying one variable to another is pass by value, and
4.0 / 3.0is not the same as4 / 3because of integer division.
That's all. I hope this post is useful to you and that you can apply it to a project you have in mind. Leave me a comment if it helped, if you want to add an opinion, or if you have any questions. And remember, if you liked it, you can also share it using the social links below. Good luck!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.