11. Variables and types

Chapter 07 wrote text directly inside fmt.Println calls. That works, but any information needed in more than one place has to be retyped every time. Variables fix that. A variable is a name that stands in for a value, so you write the value once and reuse it.

Chapters 04 and 10 showed := and = briefly. This chapter explains them fully. As before, short examples show only the lines that go inside main.

Declaring a variable

The most common shape of a variable declaration in Go:

name := "Keiko"
fmt.Println("Hello, " + name)

Two things are going on in that first line:

  • name is the variable's name. You pick it.
  • := declares a new variable and puts the value on the right into it. It does not mean "equal to" the way = does in maths.

Now name stands in for the string "Keiko", so the second line prints Hello, Keiko.

Go has a longer way to write the same declaration, with the keyword var and the type written out:

var name string = "Keiko"
fmt.Println(name)

Both make the same variable. Most Go code uses := when it has a value to start with, and var when it does not, as you will see below.

:= only works inside a function. Outside one, Go stops with syntax error: non-declaration statement outside function body. You will learn about functions in Chapter 21. For now, all your variables live inside main.

Changing a variable

A variable's value can change. Use a plain =, which is called assignment:

score := 0
fmt.Println(score) // prints 0
score = 50
fmt.Println(score) // prints 50

:= makes a new variable and = changes one that already exists. Mixing them up gives an error each way. Writing score := 50 when score already exists gives:

no new variables on left side of :=

Writing score = 50 when score does not exist yet gives:

undefined: score

Open exercises/11/01-variables.go. Change the starting value of score and run the file. The first fmt.Println should change. The second still prints 50. Why?

Types

In Go every value has a type, and so does every variable. The four types you need right now:

  • string — text, written between quotes: "hello", "a", "" (the empty string).
  • int — a whole number with no decimal point: 0, -7, 42.
  • float64 — a number with a decimal point: 3.14, 0.5, -1.0.
  • bool — exactly two values: true and false. No quotes, and all lower case. True with a capital is the error undefined: True.

When you write :=, Go works out the type from the value, so level := 7 makes an int.

fmt.Printf has a marker that prints the type of a value: %T.

fmt.Printf("%T\n", "hello") // string
fmt.Printf("%T\n", 7)       // int
fmt.Printf("%T\n", 3.14)    // float64
fmt.Printf("%T\n", true)    // bool

This is exercises/11/02-types.go.

The name float64 comes from "floating point", the way computers store numbers with decimals, and 64 is the number of bits each one uses. Go has other number types, but int and float64 are all this book needs for now.

Zero values

You can declare a variable with var and give it no value. Go then fills it with the zero value of its type:

Type Zero value
int 0
float64 0
bool false
string "" (the empty string)
var score int
var price float64
var alive bool
var name string

fmt.Println(score)
fmt.Println(price)
fmt.Println(alive)
fmt.Println("[" + name + "]") // the brackets show the empty string

Output:

0
0
false
[]

This is in exercises/11/04-zero-values.go. So a Go variable always holds a real value of its type, from the moment it is declared.

A variable keeps its type

A variable's value can change, but its type cannot. Once score is an int, it can only ever hold ints. The compiler checks this before anything runs, and this checking is why Go is called statically typed.

Open exercises/11/05-wrong-type.go. It does not compile. The first run prints:

# command-line-arguments
exercises\11\05-wrong-type.go:11:10: cannot use "fifty" (untyped string constant) as int value in assignment

Read it in the usual order: line 11, column 10. score is an int, and "fifty" is a string. Untyped string constant is Go's name for a string written directly in the code. Fix the file by assigning a number instead.

Variables must be used

Chapter 10 showed this error. Declare a variable and never read it, and the program does not compile:

name := "Keiko"
fmt.Println("hi")
name declared and not used

Assigning to a variable does not count as using it. Only reading its value does, for example by printing it. If you see this error, either use the variable or delete the line.

Constants

A value that must never change can be a constant. Write const instead of using :=:

const maxLevel = 99
fmt.Println(maxLevel) // 99

Assigning to it later is an error:

const maxLevel = 99
maxLevel = 100
cannot assign to maxLevel (neither addressable nor a map index expression)

The wording is unusual, but the line it names is the one that tries to change the constant. Use a constant for a fixed rule of your program, such as the highest level, so the name explains the number.

Variable names

You pick variable names, but Go has rules about which are allowed:

  • They can contain letters, digits, and the underscore _.
  • They cannot start with a digit. level1 is fine; 1level is not.
  • They are case sensitive. Score, score, and SCORE are three different names.
  • They cannot be one of Go's keywords: break, case, chan, const, continue, default, defer, else, fallthrough, for, func, go, goto, if, import, interface, map, package, range, return, select, struct, switch, type, var. You will meet most of these later.

Beyond the rules, follow these habits from Chapter 05:

  • Choose meaningful names. playerName beats n. hitPoints beats hp once code gets long, though hp is fine for short programs.
  • camelCase is the standard Go style: maxScore, enemyCount. Start with a lower case letter, because a capital first letter has a special meaning that Chapter 25 explains.

Printing a variable

fmt.Println does not need quotes around variable names. Quotes are only for text you type directly. To combine a label with a variable, either pass them as separate arguments or use fmt.Printf from Chapter 09:

level := 7
fmt.Println("Level:", level)     // Level: 7
fmt.Printf("Level: %d\n", level) // Level: 7

%s is for strings and %d is for whole numbers. A third marker, %v, prints any value in its usual form, which makes it the easy choice for a bool:

alive := true
fmt.Printf("Alive: %v\n", alive) // Alive: true

fmt.Println("Level:", level) prints a space between each argument automatically. fmt.Printf prints exactly what you write, so you control every character. Both are correct; fmt.Printf gives more control. Chapter 14 covers these markers in full.

Multiple assignment

Go lets you declare several variables and give them several values on one line. Names on the left pair with values on the right by position:

name, level := "Keiko", 7
fmt.Println(name, level) // Keiko 7

This groups related declarations neatly. The values can have different types, as they do here. It also enables a handy trick — swapping two variables in one step:

a, b := 1, 2
a, b = b, a
fmt.Println(a, b) // 2 1

Go reads the whole right side first, then assigns. So a, b = b, a takes the current b and a and puts them in opposite slots. The second line uses =, not :=, because a and b already exist. These examples are in exercises/11/03-multi-assignment.go.

Homework

Homework starters are in exercises/11/homework/. Each one runs as it is and prints a placeholder line. Replace that line with your own code. When a starter already has variables, the placeholder line prints them too, because Go will not compile a variable nobody reads.

Problem 1 — Player vitals

Open exercises/11/homework/01-player-vitals.go. Declare four variables called name, level, hitPoints, and alive, with values of your choice. The first must be a string, the next two whole numbers, and the fourth a bool. Print each on its own line with a label, like Name: Keiko.

Problem 2 — Type checker

Open exercises/11/homework/02-type-checker.go. Use fmt.Printf with %T to print the type of each of these five values, one per line:

  • the string "world",
  • the whole number 42,
  • the decimal 3.14,
  • the bool false,
  • the number 7.0.

Before you run it, predict the answer for the last one.

Problem 3 — Rename and reassign

Open exercises/11/homework/03-rename-and-reassign.go. The starter file has three variables a, b, and c with random-looking values. Rename them to something meaningful for their values, print them with a label, change all three to new values of the same types, then print them again.

Challenge — The zero value mystery

Open exercises/11/homework/04-zero-value-mystery.go. Declare a string variable with var and give it no value. Print its value between square brackets and its type with %T. Then give it a string value and print both again. Add a short comment block (several lines starting with //) explaining, in your own words, what a zero value is.

Stuck or finished? Open the homework solutions page.