What does iota do inside a Go const block, and what value does it start at?
answer
- only legal in one kind of declaration
- a counter, not something you assign
- counts lines, not names
- resets at every new const keyword
- first line sees zero
basics
~20 siota is a built-in counter usable only in const declarations: it is 0 on the first line of a const block and increases by one on each following line. Every new const block resets it to 0.
solid answer
~40 s`iota` is a predeclared identifier that is legal only inside a `const` declaration. Within one parenthesized `const` block it is the index of the line being evaluated: 0 on the first line, 1 on the second, and so on, and it resets to 0 at the next `const` keyword. That makes it the idiomatic way to declare a run of related integer constants, normally combined with a defined type such as `type Status int` so the compiler keeps them apart from plain ints. Because it counts lines and not names, two names declared on the same line share one iota value. Go has no enum type: `iota` plus a named type is the whole enum idiom, so the constants are ordinary ints and the zero value of the type is whichever constant got 0.
code
go · 9 linestype Status int
const (
StatusOpen Status = iota
StatusPending
StatusClosed
)
// StatusOpen == 0, StatusPending == 1, StatusClosed == 2.go deeper
Be ready to write a three-line const block that numbers statuses from zero, say what each constant equals, and state that the next const block starts counting again at zero.
Explain that iota is the index of the line being evaluated, so names sharing a line share a value, and that the constants are ordinary typed integers produced at compile time.
Show where the idiom stops protecting you: the zero value is a real status, a switch is not checked for exhaustiveness, and a decoded or database integer can name no constant at all.
Own whether a numbered enum belongs in anything outside the process at all, and who pays when the numbering has to change after other teams or stored rows depend on it.
### What `iota` actually is `iota` is a *predeclared identifier* in Go, not a keyword and not a runtime variable. You never assign to it. It is meaningful only inside a constant declaration, where the compiler substitutes an integer: the index of the ConstSpec — informally, the line — currently being evaluated inside a parenthesized `const` block. The first line sees `0`, the second `1`, the third `2`. ```go type Status int const ( StatusOpen Status = iota StatusPending StatusClosed ) ``` Here `StatusOpen` is 0, `StatusPending` is 1 and `StatusClosed` is 2. ### The counter belongs to the block `iota` resets to 0 at every `const` keyword. Two const blocks in the same file do not continue one another's numbering, and neither do const blocks in different files of the same package. If you split an enum across two `const (...)` groups, the second group restarts at 0 and you get silent duplicate values — one of the few ways this idiom bites you without any warning from the compiler. ### It counts lines, not names The increment happens once per ConstSpec, not once per declared identifier. So `const ( a, b = iota, iota )` gives `a == 0` and `b == 0`; the *next* line would see `iota == 1`. Comments and blank lines are not ConstSpecs and do not advance the counter. ### It is a compile-time construct Everything `iota` participates in is a constant expression. It is evaluated by the compiler, with exact arithmetic, before the program runs. You cannot write `iota` in a `var` declaration, in a function body, or in a struct literal; the compiler rejects it. That is also why `iota` can only ever produce numbers: constants in Go are limited to booleans, runes, integers, floats, complex values and strings, so there is no such thing as an `iota`-numbered slice or map of constants. ### Why Go uses it: the enum idiom Go deliberately has no `enum` construct. The community idiom is three parts: 1. a defined type — `type Status int` — so a `Status` is not interchangeable with a bare `int`; 2. a `const` block numbered by `iota`; 3. a `String() string` method so the values print as names rather than as digits, usually produced by `//go:generate stringer -type=Status` rather than written by hand. The defined type is the part people skip, and it is the part that buys you anything: without it, every helper that takes a `Status` will happily accept any integer expression in the program. ### What the idiom does *not* give you - **No exhaustiveness.** A `switch` over a `Status` that forgets a case compiles fine. Add a `default` branch that fails loudly rather than falling through silently. - **No range checking.** `Status(99)` is a legal conversion, and a value arriving from JSON, a database column or an RPC payload is just an integer, so it can hold a number no constant names. Validate at the boundary where the value enters your process. - **A meaningful zero value.** Whatever constant gets 0 is the zero value of the type, which means a struct field or a map miss silently reads as that status. Many teams therefore make the first constant an explicit `StatusUnknown` (or `StatusInvalid`) so that an unset field is obviously unset rather than plausibly "open". ### Offsets and variations you will see `iota` is just a number in a constant expression, so it can be shifted and offset: `StatusOpen Status = iota + 1` starts the run at 1, and arithmetic such as `1 << iota` builds bit flags. Those are all ordinary constant expressions; nothing special happens beyond the substitution of the line index. ### Common mistakes to avoid Saying "iota increments every time it appears" (it does not — it is fixed for the whole line), believing the counter survives into the next `const` block, or claiming Go's constants give you a compiler-enforced enum. In an interview, write the three-line block, state the starting value and the reset rule, then mention the defined type — that combination is what the question is really probing.
- If a const block declares two names on the same line with iota, what values do they get?The same one. `iota` counts ConstSpecs — lines — not identifiers, so in `const ( a, b = iota, iota * 10 )` both `a` and `b` are 0. The following line sees `iota == 1`. Expecting `a == 0` and `b == 1` is the usual misreading.
- Can iota appear outside a const declaration, for example in a var block?No. `iota` is defined only within a constant declaration; the compiler rejects it in a `var` block, a function body or any other expression. It is a compile-time substitution, so there is nothing for it to mean at runtime.
- Do iota-numbered constants give the type safety of an enum in other languages?Only partly. Giving them a defined type such as `Status` stops a plain `int` being passed by accident, but the underlying values are still integers. A conversion, a JSON decode or a database read can produce `Status(99)`, which no constant names, and a `switch` that misses a case still compiles. Validate at the boundary and add a loud `default`.
Think of it as the row number on a numbered list: the list restarts at the top of each new list, and a row with two items on it still has one row number.
saying these in an interview costs you the question
- Calls iota a keyword you assign a value to
- Says iota increments once per name rather than per line
- Thinks the counter continues across separate const blocks
- Claims Go has a compiler-enforced enum type
- Uses iota in a var declaration or a function body