Variables

A variable is a named place to store a value. Every Go variable has a fixed type, chosen when it's declared — either written out by you or worked out by the compiler from the starting value. This lesson covers the two ways to declare variables, zero values, declaring several at once, scope and shadowing.

Declaring with var

The full form is var name type = value. You can leave out the type when there's a value (Go infers it), or leave out the value when there's a type (the variable starts at its zero value):

GO
package main

import "fmt"

func main() {
	var city string = "Lisbon"
	var population = 545_000 // type inferred: int
	var rainfall float64     // no value: starts at 0

	fmt.Println(city, population, rainfall)

	rainfall = 774.2 // assign a new value with =
	population += 1000
	fmt.Println(city, population, rainfall)
}
Output
Lisbon 545000 0
Lisbon 546000 774.2

Underscores inside a number, as in 545_000, are just for readability.

Short declarations with :=

Inside functions, the short form name := value declares a variable and infers its type. It's what Go programmers use most of the time:

GO
package main

import "fmt"

func main() {
	name := "Ada"
	age := 36
	height := 1.65
	admin := false

	fmt.Printf("%s is %d, %.2f m tall, admin: %t\n", name, age, height, admin)
	fmt.Printf("types: %T %T %T %T\n", name, age, height, admin)
}
Output
Ada is 36, 1.65 m tall, admin: false
types: string int float64 bool

The %T verb prints a value's type. Whole-number literals become int and numbers with a decimal point become float64.

Remember the difference: := declares a new variable, = assigns to an existing one. Using := twice for the same name in the same scope is an error, and so is = with a name that hasn't been declared:

GO
package main

import "fmt"

func main() {
	count := 1
	count := 2
	total = 10
	fmt.Println(count)
}
Compiler error
./main.go:7:8: no new variables on left side of :=
./main.go:8:2: undefined: total

:= only works inside functions. At package level, outside any function, you must use var.

Zero values

Go has no uninitialised variables. A variable declared without a value holds its type's zero value:

GO
package main

import "fmt"

func main() {
	var i int
	var f float64
	var s string
	var b bool
	var p *int
	var list []string

	fmt.Println(i, f, b)
	fmt.Printf("%q\n", s)
	fmt.Println(p == nil, list == nil, len(list))
}
Output
0 0 false
""
true true 0
TypeZero value
Numbers0
string"" (empty string)
boolfalse
Pointers, slices, maps, channels, functions, interfacesnil
Arrays and structsEvery element or field set to its own zero value

Well-designed Go types are useful at their zero value: an empty string, a zero count, or a nil slice you can append to straight away.

Several variables at once

GO
package main

import "fmt"

var ( // a group of package-level variables
	appName = "Inventory"
	version = 3
)

func main() {
	x, y := 10, 20
	var width, height int = 640, 480
	first, last := "Grace", "Hopper"

	x, y = y, x // swap in one statement
	fmt.Println(appName, version)
	fmt.Println(x, y, width, height, first, last)
}
Output
Inventory 3
20 10 640 480 Grace Hopper

In a multiple assignment, all the values on the right are evaluated before any variable is changed, which is why x, y = y, x swaps the two without a temporary variable.

:= with several names is allowed as long as at least one of them is new; the others are simply assigned. You'll see this constantly with errors:

GO
package main

import (
	"fmt"
	"strconv"
)

func main() {
	a, err := strconv.Atoi("42")
	b, err := strconv.Atoi("x7") // b is new, err is reused
	fmt.Println(a, b, err)
}
Output
42 0 strconv.Atoi: parsing "x7": invalid syntax

Scope and shadowing

A variable exists from its declaration to the end of the block it was declared in. A variable declared in an inner block with the same name as an outer one shadows it — the inner one is a separate variable:

GO
package main

import "fmt"

func main() {
	level := "outer"
	if true {
		level := "inner" // a new variable, only inside this block
		fmt.Println(level)
	}
	fmt.Println(level)

	count := 0
	if true {
		count = 5 // plain = changes the outer variable
	}
	fmt.Println(count)
}
Output
inner
outer
5

Accidental shadowing — typing := where you meant = inside an if — is a classic Go bug. If a variable mysteriously keeps its old value after a block, check for a stray colon.

The blank identifier

Every declared local variable must be used. When a function returns a value you don't need, assign it to _:

GO
package main

import (
	"fmt"
	"strconv"
)

func main() {
	n, _ := strconv.Atoi("123") // ignore the error (only when you're sure it can't fail)
	for _, word := range []string{"red", "green"} {
		fmt.Println(n, word)
	}
}
Output
123 red
123 green

Try it yourself

Declare variables for a product and print a line describing it. Then try declaring a variable you never use and read the compiler's message.

Try it yourself · main.go
Edit the code, copy it into main.go in a new folder and run it with go run main.go (Go 1.27 or later). How to install Go
Output
Desk lamp: 34.90 (12 in stock, on sale: false)
Next: Go's basic types.