Variables & Constants

Go · Lesson 6 of 32 7 min read Updated

A variable is a named place in memory that holds a value your program can change, such as a student's marks or the items in a cart. A constant is a named value that never changes, such as the GST rate. Go gives you a few ways to create each one, and it is strict about using them.

In this lesson you will learn var and the short := form, the zero value that every Go variable starts with, and how to build simple enumerations with const and iota.

Declaring variables

The full form uses the var keyword, a name, a type and an optional starting value. Inside functions, most Go code uses the shorter := form, which works out the type from the value.

Go
package main

import "fmt"

func main() {
	var name string = "Aarav"   // name, type and value
	var age = 21                // type worked out from the value: int
	city := "Lucknow"           // short form, only inside functions

	fmt.Println(name, age, city)

	age = 22 // assignment: change the value, no new variable
	fmt.Println("Next year:", age)
}
Output
Aarav 21 Lucknow
Next year: 22

Read := as "declare and assign". Use plain = later when you only want to change the value. The type never changes: after age = 22, writing age = "twenty" is a compile error, because age is an int for its whole life.

Names in Go use camelCase: totalMarks, ticketPrice. Short names such as i, n or err are normal for variables that live only a few lines.

Zero values

In Go, a variable declared without a value is never "undefined" or full of garbage. It gets the zero value of its type:

TypeZero value
Numbers (int, float64, ...)0
string"" (empty string)
boolfalse
Pointers, slices, maps, channels, functions, interfacesnil
Go
package main

import "fmt"

func main() {
	var marks int
	var passed bool
	var nickname string
	var price float64

	fmt.Println(marks, passed, price)
	fmt.Printf("%q\n", nickname)
}
Output
0 false 0
""

%q prints a string in double quotes, which makes the empty string visible. Zero values are useful: a counter can start at zero without any setup, and many Go types are designed so that their zero value is ready to use.

Several variables at once

You can declare or assign several variables in one line. The right side is fully evaluated first, which gives you a neat way to swap two values without a temporary variable:

Go
package main

import "fmt"

func main() {
	batsman, runs := "Rohan", 48
	fmt.Println(batsman, runs)

	first, second := "Meera", "Isha"
	first, second = second, first
	fmt.Println(first, second)

	var (
		train    = "Shatabdi"
		coach    = "C3"
		seat int = 42
	)
	fmt.Println(train, coach, seat)
}
Output
Rohan 48
Isha Meera
Shatabdi C3 42

The var ( ... ) block groups related declarations and is common at package level, outside any function, where := is not allowed.

Go's strict rules for variables

Unused variables are errors. If you declare a local variable and never read it, the program does not compile:

Go
func main() {
	total := 0
	fmt.Println("hello")
}
Output
./main.go:6:2: declared and not used: total

This rule catches typos and dead code. When a function returns a value you truly do not need, assign it to the blank identifier _, which throws the value away.

:= needs at least one new name. x := 1 followed by x := 2 in the same block fails with "no new variables on left side of :=". Use x = 2.

Shadowing. A := inside an inner block creates a new variable that hides the outer one with the same name. This is a common source of bugs:

Go
package main

import "fmt"

func main() {
	fee := 500
	member := true
	if member {
		fee := fee - 100 // new variable, only inside the if block
		fmt.Println("Inside:", fee)
	}
	fmt.Println("Outside:", fee)
}
Output
Inside: 400
Outside: 500

The discount was lost because the inner fee disappeared at the closing brace. Writing fee = fee - 100 (plain =) changes the outer variable, so Outside: 400 would print.

Constants

Use const for values fixed when you write the program. Constants can be numbers, strings or booleans, and they must be known at compile time, so you cannot set one from a function call that runs later.

A constant written without a type is untyped. It takes whatever numeric type the situation needs, which makes constants flexible:

Go
package main

import "fmt"

const gstPercent = 18      // untyped constant
const shopName = "Kabir Mobiles"

func main() {
	var price float64 = 1299.0
	tax := price * gstPercent / 100
	fmt.Println(shopName)
	fmt.Println("Tax:", tax)
}
Output
Kabir Mobiles
Tax: 233.82

gstPercent acted as a float64 here. If it were an int variable, price * gstPercent would fail with "mismatched types float64 and int", because Go never mixes numeric types silently.

Enumerations with iota

Go has no enum keyword. Instead, inside a const block, the special word iota counts 0, 1, 2 and so on, one step per line. Lines without a value repeat the previous expression:

Go
package main

import "fmt"

const (
	Pending = iota // 0
	Packed         // 1
	Shipped        // 2
	Delivered      // 3
)

const (
	_  = iota             // skip 0
	KB = 1 << (10 * iota) // 1 << 10
	MB                    // 1 << 20
	GB                    // 1 << 30
)

func main() {
	fmt.Println(Pending, Packed, Shipped, Delivered)
	fmt.Println(KB, MB, GB)
}
Output
0 1 2 3
1024 1048576 1073741824

In the second block, iota is 1 on the KB line, so 1 << 10 is 1024. The << operator shifts bits left, which multiplies by 2 for each step. In Structs & Methods you will give such constants their own type and a readable name.

Common mistakes

  • Using := outside a function. At package level you must write var x = 5.
  • Accidental shadowing with := inside if or for blocks, as shown above.
  • Expecting constants from function calls. const today = time.Now() does not compile; use a variable.
  • Mixing types. An int variable and a float64 variable cannot be added without conversion.

Key points

  • var name type = value is the full form; name := value is the short form inside functions.
  • Every variable starts with its zero value: 0, "", false or nil.
  • Unused local variables are compile errors; use _ to discard values you do not need.
  • := in an inner block can shadow an outer variable; use = to change the outer one.
  • const values are fixed at compile time, and iota numbers constants in a block.

Exercise

A railway booking app needs four seat classes: Sleeper, AC3, AC2 and AC1, numbered from 1 (not 0) with iota. Declare them as constants. Then declare a variable fare with the zero value, set it to 1450, and print the class number for AC3 and the fare.

Show solution
Go
package main

import "fmt"

const (
	Sleeper = iota + 1
	AC3
	AC2
	AC1
)

func main() {
	var fare int
	fmt.Println("Starting fare:", fare)
	fare = 1450
	fmt.Println("AC3 class number:", AC3)
	fmt.Println("Fare:", fare)
}
Output
Starting fare: 0
AC3 class number: 2
Fare: 1450

Each line repeats iota + 1, so the values are 1, 2, 3 and 4. The variable starts at its zero value and is then changed with plain =.

Quick Quiz

1. What is the value of var count int before anything is assigned?

2. Where can you use the short form x := 10?

3. What does iota equal on the third line of a const block?

4. What happens when you declare a local variable and never use it?

Learn Go with a mentor

Free lessons get you started. Our Programming & Software Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call