topic logo
Go ⇢ Unit 2

Variables

declaration

Summary

This unit explains the fundamental data types for numbers, boolean values and strings. It shows how variables are declared, initialized and assigned.

Background

The backbone of each program consists of it’s variables. Variables generally have three parts:

  • a type,
  • an identifier and
  • a value.

For example: the variable with the identifier “temperature” and the type “int” (integer) could have the value 20. It can also carry other values, like 10, 100 or even 1,000,000 - but not 12.3, because that’s a floating point number and not an integer.

Go variables are statically typed. Once a variable is declared, it will keep these attributes until it runs out of scope. Simply said, you can’t change the type of a variable during it’s lifetime. But you can convert and assign it to a different variable.

Comments

Comments are part of most programs and help you to find your way and understand the thought process and crucial challenges that the original author faced during development. Before I dig deeper into the subject of variables, let me show you how to create comments in Go source files, as I will use these in the examples further on:

// Two slashes start a comment that lasts until the end of the line.

x = 2 + 2 // These comments can start after a statement.

/*
Slash-star starts a multi-line comment that lasts until the
next star-slash.
*/

Declaring a variable

Variables are born when they are declared. Every variable needs to be declared before it can be used. This is done with one of the few keywords called “var”, followed by the variable identifier and it’s type.

var x int
x = 10
x = 20

The above statement declared a variable called “x” which has the type integer. The second and third line assign different values to the variable.

Multiple variables of the same type can be declared at the same time by separating the identifiers with commas.

var x, y, z int
x = 10
y = 20
z = x + y

Multiple variable declarations with different types can be combined by putting them into parentheses after the var keyword:

var (
    x, y int
    z bool
)

Variables can also be initialized during declaration:

var x, y int = 10, 20

Implicit variable declaration

So far we explicitly told the variables what type they have during declaration. The Go programming language also allows you to do the same implicitly:

var x, y = 10, true

The above statement declares the variables “x” and “y” and determines their type from the values that are assigned to them. So “x” will be an “int” and “y” a bool type with the values 10 and true assigned.

An even shorter way to do this is with the := colon-equals operator:

x, y := 10, true

Variables can only be declared once within their scope. When you try to do it a second time, the compiler will complain:

x, y := 10, true
x := 20

▶ compiler error: main.go:7: no new variables on left side of :=

Instead do:

x, y := 10, true
x = 20

Hint

I will use the “▶” symbol to indicate the output of a program or the tool-chain.

How long do variables live?

Variables have a “scope”. Simply said, a scope is a block that is defined by two matching braces “{..}”. For example, a function is a block, as is an if statement. Variables declared outside of functions have the scope of their package.

// package block
var x int

func main() {
    // function block begins
    var y int

    {
        // nested block begins
        var z int
        z = x + y
        ..
        // nested block ends
    }

    // z no longer exists
    y = x // ok
    // function block ends
}

Variable-scope interaction

You can not declare two variables with the same name in the same scope twice. However, you can address variables from parent scopes (e.g. function variables within an if statement). You can also declare variables with a name that has been used for a variable declaration in the parent scope. The newly created variable will be independent of the parent scope variables and can is not bound to it’s type or value:

func main() {
    var x int = 0
    var y int = 10
    {
        var x bool = true
        // x == true (from this scope)
        // y == 10 (from parent scope, because it's not declared here)
    }
    // x == 0 (from this scope)
    // y == 10 (from this scope)
}

The blank identifier

Go programs have a special variable called the “blank identifier”, which is represented by the “_” underscore character. This is used when you wish to discard the result of an assignment:

_ = x + y

Go functions can have multiple return values and if you want to discard one of them, you can use the blank identifier.

Fundamental types

To get you started, I’ll introduce the fundamental types that you will need as basic building block for most of your programs:

  • bool contains a truth value, which can be true or false.
    • Defaults to false.
  • int is an integer number (e.g. not fractional). Depending on the system it’s size limits are either 32 bit (+/- 2147483647) or 64 bit (+/- 9223372036854775807). If you know what the limits of your variables will be or want to be explicit, you can also use one of the following variants: int8, int16, int32, int64 and their unsigned counterparts uint, uint8, uint16, uint32, uint64. However, you’ll need to convert each time you want to perform operations with multiple of these different types.
    • Defaults to 0.
  • float32 and float64 are floating point or fractional number types. These conform to IEEE-754 32-bit and IEEE-754 64-bit floating point numbers.
    • Defaults to 0.0.
  • string is a sequence of characters, also known as text. Go strings are made up of Unicode code points, so they can be used to store a variety of scrips, like the Latin alphabet, Greek and Russian characters, Chinese and Japanese symbols and much more.
    • Defaults to empty string: “”.
  • byte is just an alias to uint8 and is used to represent one byte of data

Getting the type of a variable

The “reflect” package of the standard library exports a function called “TypeOf” that can be used to get the type of a variable:

import "reflect"
...
var x int
fmt.Println(reflect.TypeOf(x))

▶ int

Application

The example application of this unit is fairly simple. It declares a few variables in a variety of ways, assigns values to some of them and then prints their values and their type.

main.go - declaring variables
package main

import (
    "fmt"
    "reflect"
)

var (
    x int
    y int = 10
    z     = x + y
    q byte
)

func main() {

    a, b := 1.1, true
    c := "spaghetti"
    fmt.Println(x, y, z, a, b, c, q)
    fmt.Println(reflect.TypeOf(x))
    fmt.Println(reflect.TypeOf(y))
    fmt.Println(reflect.TypeOf(z))
    fmt.Println(reflect.TypeOf(a))
    fmt.Println(reflect.TypeOf(b))
    fmt.Println(reflect.TypeOf(c))
    fmt.Println(reflect.TypeOf(q))
}

▶ 0 10 10 1.1 true spaghetti 0
▶ int
▶ int
▶ int
▶ float64
▶ bool
▶ string
▶ uint8

Conclusion

In this unit I introduced how to work with basic variables, which will be an essential part of most examples from here on.