env.dev

Constants in Go

const keyword, iota, and typed constants

The const Keyword

Go has first-class support for constants through the const keyword. Constants in Go must be expressible as compile-time values — they can be numbers, strings, booleans, or expressions composed of other constants. Unlike variables, constants in Go have no memory address and cannot be referenced with a pointer.

go
const MaxRetries = 3
const DefaultTimeout = 30 * time.Second
const APIBaseURL = "https://api.example.com/v1"

// Grouped constants
const (
    StatusOK    = 200
    StatusNotFound = 404
    StatusError = 500
)

Go constants can be typed or untyped. An untyped constant has a "kind" rather than a fixed type, which gives it higher precision and more flexible use. The constant 3.14159 can be used wherever a float32, float64, or even a user-defined float type is expected. A typed constant is restricted to its declared type.

go
// Untyped constant — can be used as float32, float64, etc.
const Pi = 3.14159265358979323846

// Typed constant — restricted to float64
const TypedPi float64 = 3.14159265358979323846

var f32 float32 = Pi       // OK: untyped constant adapts
// var f32 float32 = TypedPi  // Error: cannot use float64 as float32

iota: The Constant Generator

Go's iota is a powerful tool for generating sequences of related constants. It starts at 0 in each const block and increments by 1 for each constant specification. Combined with expressions, iota can generate bitmasks, powers of two, offsets, and other patterns.

go
// Simple enumeration
type Weekday int

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

// Bitmask flags
type Permission uint

const (
    Read    Permission = 1 << iota  // 1
    Write                            // 2
    Execute                          // 4
)

// Byte size units
const (
    _  = iota               // skip 0
    KB = 1 << (10 * iota)   // 1024
    MB                       // 1048576
    GB                       // 1073741824
    TB                       // 1099511627776
)

The blank identifier _ can skip values in an iota sequence. This is commonly used to skip 0 so that the zero value of the type is distinct from any named constant, which helps catch uninitialized variables.

Typed Constants and Enumerations

Go does not have a dedicated enum type, but the idiomatic pattern is to define a named type and a set of typed constants using iota. This gives you type safety — you cannot accidentally pass an untyped integer where a Weekday is expected (though the type system allows explicit conversion).

go
type Direction int

const (
    North Direction = iota
    East
    South
    West
)

// String method for readable output
func (d Direction) String() string {
    names := [...]string{"North", "East", "South", "West"}
    if d < North || d > West {
        return "Unknown"
    }
    return names[d]
}

func move(d Direction) {
    fmt.Println("Moving", d)
}

move(North)  // "Moving North"
// move(42)  // Cannot use 42 (untyped int) as Direction

Built-in Constants

Go has only three predeclared constants: true, false, and iota. The standard library provides additional constants in packages like math, os, and unicode:

go
import "math"

math.Pi    // 3.141592653589793
math.E     // 2.718281828459045
math.Phi   // 1.618033988749895 (golden ratio)
math.Ln2   // 0.6931471805599453
math.Ln10  // 2.302585092994046
math.MaxFloat64  // ~1.8e308
math.MaxInt64    // 9223372036854775807
math.MinInt64    // -9223372036854775808

Common Patterns

  • Group related constants in a const ( ... ) block. Use separate blocks for unrelated groups.
  • Exported constants start with an uppercase letter. Unexported constants start with lowercase and are scoped to the package.
  • Use iota for sequential enumerations but be cautious about adding values in the middle — it shifts all subsequent values and can break serialized data.
  • Skip the zero value with _ = iota so the zero value of the type signals "uninitialized" rather than accidentally matching a valid constant.
  • Use the go generate tool with stringer to automatically generate String() methods for constant types.