Constants and iota

Some values never change. The speed of light, the name of your application, the maximum number of retries before giving up: once these are set, they stay set for the life of the program. In Go, a constant is how you declare such a value, and the compiler enforces that it never changes.

You declare a constant with const:

const Greeting = "Hello"

Constants can hold strings, whole numbers, decimal numbers (what Go calls floats, covered properly in a later lesson), or booleans. They cannot hold values that need to be computed at runtime, such as the result of reading a file or the current time.

const versus var

const works at the top level of a file, just like var, and also inside functions. The crucial difference is that the value of a constant must be known to the compiler before the program runs:

const MaxUsers = 100      // fine, a fixed number
const Pi = 3.14159        // fine, a decimal literal

var count = 42
const Copy = count        // error, count is a variable (a runtime value), not a constant

Anything that would require running code to produce its value (reading a file, measuring time, calling a function that does real work) is not allowed in a const. In return for this restriction, constants can be used anywhere Go requires a compile-time value, and the compiler can often inline them by replacing uses with the literal value.

Typed versus untyped constants

Most constants you write are untyped. const Pi = 3.14159 does not have a fixed type; Go gives it one later, based on where it is used:

const Pi = 3.14159

var small float32 = Pi    // Pi is treated as float32 here
var big float64 = Pi      // same Pi, treated as float64 here

You can pin a type explicitly if you want:

const MaxUsers int = 100

var bad float64 = MaxUsers              // error: cannot use MaxUsers (int) as float64
var good float64 = float64(MaxUsers)    // fine, with an explicit conversion

Once MaxUsers has a fixed type, every use has to match that type or use an explicit conversion.

Prefer untyped constants

Leave your constants untyped (no explicit type) unless a specific API forces one. An untyped constant adapts to whatever numeric context it ends up in, so the same const Pi = 3.14159 works as a float32 in one call and a float64 in another, with no conversions or duplicates.

Grouped declarations

When you have several related constants, group them in a parenthesised block:

const (
    StatusPending  = "pending"
    StatusActive   = "active"
    StatusArchived = "archived"
)

This is purely a syntactic convenience. It keeps related constants together and saves you from writing const on every line.

iota for numbered constants

Inside a grouped const block, the identifier iota is a counter that starts at 0 on the first line and increments by one on each subsequent line:

const (
    Sunday    = iota // 0
    Monday           // 1
    Tuesday          // 2
    Wednesday        // 3
)

Each line after the first reuses the expression from the line above (which is iota), so you do not need to write it again. By the time the block ends, you have a tidy set of numbered constants with no magic numbers or hand-counted integers. This is Go's idiom for enumerations.

More iota tricks later

iota can also be used for bit flags, skipped values, and custom numbering schemes. Those patterns are covered in the Idioms chapter.

Task

Use a grouped const block with iota to define four seasons in this order: Spring, Summer, Autumn, Winter. Print them all on one line with fmt.Println so you can see the values the compiler assigned.

Expected output
0 1 2 3