Background:
Constants in Go are an integral part of the language. The identifier iota is used for grouped constants with auto-numbers, introduced in the earliest versions of Go to simplify the declaration of logically related values.
Issue:
Many developers make mistakes when working with iota, misinterpreting how and where it increments and how it applies in complex declaration patterns. This leads to incorrect values even for simple enum-like structures.
Solution:
iota allows for declaring sequential constants and conveniently assembling bit flags. It starts at zero in each new constant group. Each new const block or new line in the block increments the value of iota.
Code example:
// Example of a flag mask and enum with iota const ( _ = iota // skip zero FlagRead // 1 FlagWrite // 2 FlagExecute // 3 ) const ( ( // bit flags FlagA = 1 << iota // 1 << 0 = 1 FlagB // 1 << 1 = 2 FlagC // 1 << 2 = 4 ) )
Key features:
Can iota increment outside of a const block or when declaring a constant not in a group?
No, iota works only within a const group. In a single declaration, it is always 0.
const A = iota // 0 const B = iota // 0 (new block)
What happens if not all values in the group use iota?
Only those explicitly specified will receive a new value; the rest inherit the expression from the previous line.
const ( A = iota // 0 B // 1 C = 10 // 10 D // 10 (not iota, but repeating the expression from C) )
How to declare bit masks using iota?
Bit masks are implemented through shifts: 1 << iota.
const ( F1 = 1 << iota // 1 F2 // 2 F3 // 4 )
An engineer declares bit flags in different groups, thinking that iota will continue counting:
const ( FlagA = 1 << iota // 1 FlagB // 2 ) const ( FlagC = 1 << iota // 1 – not 3 as expected! )
Pros:
Cons:
All related constants are combined into one group:
const ( FlagA = 1 << iota FlagB FlagC )
Pros:
Cons: