Skip to main content
Variables and constants

Variables and constants

7 minutes read

Filed underGo Programming Languageon

Learn how Go names values — the var keyword, short declarations, and constants. Understand type inference, zero values, and the difference between mutable and immutable bindings.

Naming values

Every program works with values. Some of those values change as the program runs — a counter that increments, a status that flips from pending to complete. Others never change — a maximum retry count, the value of pi, the name of an application.

Go gives you two tools for naming values: variables for things that change, and constants for things that do not.

Variables

A variable is a named storage location. Its value can be reassigned at any point during the program's execution.

The var keyword

The most explicit way to declare a variable is with the var keyword, followed by the name, the type, and optionally an initial value:

var age int          // declared with zero value: 0
var name string      // zero value: ""
var active bool      // zero value: false
var score int = 100  // declared with explicit value

When you declare a variable without assigning a value, Go initializes it to its zero value — the default value for that type. Every type has one: 0 for integers, 0.0 for floats, false for booleans, "" for strings. There is no such thing as an uninitialized variable in Go.

If you provide an initial value, Go can infer the type — you do not need to name it explicitly:

var age = 30           // inferred as int
var greeting = "Hello" // inferred as string

Inference uses the default type

When Go infers a type from an untyped literal, it uses the default type for that kind of value. A bare integer like 42 defaults to int. A bare float like 3.14 defaults to float64. If you need a specific type, declare it explicitly: var x float32 = 3.14.

Short variable declaration

Inside a function, you can omit both var and the type using the := operator. It declares and initializes the variable in one step:

age := 30
greeting := "Hello"
isActive := true

The type is always inferred from the right-hand side. Short declarations are the most common form of variable declaration in Go — they are concise and keep functions readable.

One important restriction: := cannot be used at package level. It is only valid inside functions.

package main

counter := 0 // compile error: not inside a function

func main() {
    counter := 0 // fine
}

Reassigning and reusing :=

:= requires that at least one variable on the left side is new. This allows you to reuse it when declaring a new variable alongside an existing one:

x := 10
x, y := 20, 30 // valid: y is new, x is reassigned

If all variables on the left already exist, use plain = for reassignment:

x := 10
x = 20 // reassignment, not a new declaration

Multiple variables

You can declare multiple variables on a single line:

var x, y, z int = 1, 2, 3
a, b := "hello", true

Or group them inside a var block — common for related declarations at the top of a function or at package level:

var (
    host    = "localhost"
    port    = 8080
    timeout = 30
)

Package-level vs function-level

Variables can be declared at two scopes:

Package-level variables are declared outside any function. They are accessible throughout the entire package and initialized before main runs.

Function-level variables are declared inside a function. They exist only for the duration of that function call and are invisible outside it.

package main

var serverHost = "localhost" // package-level

func connect() {
    port := 5432 // function-level
    fmt.Println(serverHost, port)
}

Unused variables are a compile error

Go refuses to compile a program that declares a local variable without using it. This is intentional — it prevents dead code and keeps functions clean. Package-level variables are exempt from this rule.

Constants

A constant is a named value that cannot change after it is set. It is not a variable with a guard — it is evaluated entirely at compile time and never occupies a memory location at runtime.

The const keyword

Constants are declared with const:

const maxRetries = 3
const appName = "MyApp"
const pi = 3.14159265358979

Like variables, constants support grouped declarations:

const (
    maxRetries = 3
    timeout    = 30
    appName    = "MyApp"
)

What can be a constant

Not every value qualifies as a constant. The compiler must be able to determine its value before the program runs. Valid constant values include:

  • Boolean literals: true, false
  • Integer, float, and complex literals
  • String and rune literals
  • Expressions that can be evaluated at compile time: 1 << 8, 2 * 3.14, 1 < 2
  • Calls to certain built-in functions: len, cap, real, imag, complex
const bufferSize = 1 << 8  // 256
const isDebug = false
const greeting = "Hello"
const alwaysTrue = 1 < 2   // evaluated at compile time — true

Function calls that produce runtime values — like reading from a file or calling time.Now() — cannot be used as constants.

Typed and untyped constants

Constants in Go come in two forms: typed and untyped.

A typed constant carries an explicit type and can only be directly assigned to a variable of that same type:

const maxRetries int = 3

var x int   = maxRetries // fine
var y int64 = maxRetries // compile error: cannot use maxRetries as int64

An untyped constant has no fixed type. It carries a kind (integer, float, string, or boolean) and adapts to whatever type is expected at the point of use:

const maxRetries = 3 // untyped integer constant

var x int     = maxRetries // fine
var y int64   = maxRetries // fine — adapts to int64
var z float64 = maxRetries // fine — adapts to float64

Prefer untyped constants

Leave constants untyped unless you have a specific reason to restrict them. Untyped constants are more flexible — they work wherever a compatible kind is expected, without explicit conversion.

iota

When you need a sequence of related integer constants, Go provides iota — a counter that starts at zero and increments by one with each entry in the block:

const (
    Sunday    = iota // 0
    Monday           // 1
    Tuesday          // 2
    Wednesday        // 3
    Thursday         // 4
    Friday           // 5
    Saturday         // 6
)

iota resets to zero at the start of every new const block. It is the idiomatic Go way to define enumerations.

Variables vs constants

Both variables and constants can be declared at package or function level, and both support grouped declarations with braces. The differences are more significant than they might appear:

varconst
Value can changeyesno
Evaluated atruntimecompile time
Short form (:=)yes (functions only)no
Can remain unusedno (local only)yes

The unused rule is worth emphasizing: a local variable that is declared but never referenced is a compile error. Constants are always exempt — they can exist purely for documentation or future use without the compiler objecting.