Go (Golang) Tutorial 0/45 lessons ~6 min read Lesson 5

    Constants & Operators

    Constants in Go are compile-time values declared with const.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Constants in Go are compile-time values declared with const. Combined with iota, they create elegant enumerations for HTTP status codes, error codes, and state machines. Operators follow familiar arithmetic, comparison, and logical rules with Go's strict typing.

    Understanding operator precedence, short-circuit evaluation with && and ||, and the difference between == and deep equality for slices (via slices.Equal or reflect) prevents subtle comparison bugs in API handlers and test assertions.

    This lesson builds the expression vocabulary you will use in every conditional, loop, and business rule throughout the course — from discount calculations to permission checks in middleware.

    The story

    A Cloudflare Workers routing configurator maps HTTP status codes and priority tiers to upstream pool weights. Constants like StatusBadGateway = 502 and bit-mask flags for feature toggles keep magic numbers out of the codebase — when an on-call engineer reads the diff at 3 AM, named constants explain intent instantly.

    Operators combine arithmetic for rate limiting (requests * windowSeconds), comparisons for threshold alerts, and logical AND for feature flags — the glue between metrics and automated remediation.

    Understanding the topic

    Key concepts

    • const declares immutable values; typed and untyped constants exist.
    • iota resets to 0 in each const block and increments per line — ideal for enums.
    • Arithmetic: + - * / % with integer division truncating toward zero.
    • Comparison: == != < <= > >= — struct equality compares fields if comparable.
    • Logical: && || ! short-circuit; bitwise: & | ^ << >> &^.
    • Untyped constants participate in flexible arithmetic until assigned to typed variable.
    text
    flowchart LR
    A[Operands] --> Arith[+ - * /]
    A --> Compare[== != < >]
    A --> Logical[&& || !]
    Arith --> Result[Expression]

    Step-by-step explanation

    1. Declare constants individually or in const ( ) blocks.
    2. iota starts at 0; each subsequent line increments unless reset with new const block.
    3. Expressions in const must be compile-time computable.
    4. Operators apply to typed operands; mixing types requires conversion.
    5. && stops if left is false; || stops if left is true.
    6. Bitwise ops work on integer types for flags and permissions.

    Practical code example

    HTTP-style status constants with iota and operator usage in authorization checks:

    go
    package main
    import "fmt"
    type Role int
    const (
    RoleGuest Role = iota
    RoleUser
    RoleAdmin
    )
    const (
    PermRead = 1 << iota // 1
    PermWrite // 2
    PermDelete // 4
    )
    func hasPermission(granted, required int) bool {
    return granted&required == required
    }
    func main() {
    role := RoleAdmin
    perms := PermRead | PermWrite
    fmt.Printf("role=%d admin=%v read=%v write=%v delete=%v\n",
    role, role == RoleAdmin,
    hasPermission(perms, PermRead),
    hasPermission(perms, PermWrite),
    hasPermission(perms, PermDelete))
    }

    Line-by-line code explanation

    • const MaxRetries = 3 declares an untyped constant usable in any numeric context.
    • const ( StatusOK = 200; StatusBadGateway = 502 ) groups related HTTP constants.
    • iota in a const block auto-increments — ideal for enum-like priority levels.
    • priority := baseWeight * (1 + retryCount) applies arithmetic with typed operands.
    • if latencyMs > threshold && errorRate > 0.05 combines comparison and logical operators.
    • enabled := flags & FeatureRateLimit != 0 uses bitwise AND to test a feature flag bit.
    • rate := float64(success) / float64(total) requires explicit conversion between numeric types.
    • switch { case latencyMs >= 500: ... } uses operator expressions in switch cases without a tag.

    Key takeaway: iota enums are idiomatic Go — no separate enum keyword. Bit flags with iota and bitwise ops model RBAC permissions cleanly.

    Real-world use

    Where you'll use this in production

    • HTTP status codes and error code enumerations in API packages.
    • State machines for order lifecycle (Pending, Shipped, Delivered).
    • Feature flags and permission bitmasks in authorization middleware.
    • Time constants (time.Second, time.Minute) built with typed duration arithmetic.

    Best practices

    • Use iota for related constant groups; add String() method for debug output.
    • Name constants in PascalCase if exported, camelCase if package-private.
    • Use typed constants (const StatusOK = 200) for API clarity.
    • Prefer const over var for values that never change.
    • Document iota blocks with a comment on the first line for go doc.
    • Use parentheses in complex expressions for readability.

    Common mistakes

    • Assuming iota continues across separate const blocks — it resets.
    • Using == to compare slices — compares pointers, not contents.
    • Integer division surprise: 5/2 is 2, not 2.5 — use float64 conversion.
    • Modifying const — compile error, but trying via pointer tricks fails.
    • Confusing & (address) with & (bitwise AND) depending on context.

    Advanced interview questions

    Q1BeginnerWhat is iota?
    A counter starting at 0 in each const block, incrementing by 1 per line — used for enumerations and bit flags.
    Q2BeginnerShort-circuit evaluation?
    && skips right operand if left is false; || skips if left is true — prevents nil dereference in chains.
    Q3IntermediateTyped vs untyped constants?
    Untyped constants adapt to context (e.g., 42 fits int, float64); typed constants require conversion.
    Q4IntermediateCompare two slices for equality?
    Use slices.Equal (Go 1.21+) or loop; == compares slice headers (pointer, len, cap), not elements.
    Q5AdvancedDesign permission system with iota bit flags.
    const ( Read = 1<

    Summary

    const and iota create clean enumerations and bit flags. Operators require matching types; conversions are explicit. Short-circuit && and || enable safe nil-check chains. Never use == for slice content comparison — use slices.Equal. Next lesson: formatted I/O with fmt, bufio, and os packages.

    Ready to mark this lesson complete?Track your journey across the entire course.