iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
💻

iota is not always zero when it first appears

に公開

Another quick tip.

In Section 3.6.1, "The iota Constant Generator," of The Go Programming Language, which was discussed during the "16th 'The Go Programming Language' Online Reading Circle", the book states:

In a const declaration, the value of iota begins at zero and increments by one for each item in the sequence.

However, Yoshiki Shibata, the translator and organizer of the reading circle, provided an explanation regarding this point. This post is about that.

Originally, const has a feature where the same value as the preceding constant is set when written this way:

package main

import "fmt"

const (
    one = 1
    two
    three
    four
)

func main() {
    fmt.Println(one, two, three, four)
    // Output:
    // 1 1 1 1
}

By combining this property with the iota constant generator, you can set values that increment one by one.

package main

import "fmt"

const (
    one = 1 + iota
    two
    three
    four
)

func main() {
    fmt.Println(one, two, three, four)
    // Output:
    // 1 2 3 4
}

So, is the initial value of iota always zero? It’s a bit more nuanced than that. For example:

package main

import "fmt"

const (
    zero = "0"
    one  = 1
    two
    three
    four = iota
)

func main() {
    fmt.Println(zero, one, two, three, four)
    // Output:
    // 0 1 1 1 4
}

If you write it this way, the value of iota when it appears is 4. In other words, iota is being counted from the start, even before it (apparently[1]) appears.

If you assume that the value of iota is always zero when it appears and accidentally write code like this:

package main

import "fmt"

const (
    one = 1 + iota
    two
    three
    four
    zero = iota
)

func main() {
    fmt.Println(zero, one, two, three, four)
    // Output:
    // 4 1 2 3 4
}

... zero will not be zero, resulting in an unexpected value. It's embarrassing, but I actually got stuck on this pattern in the past (it didn't pass the tests, and I spent some time wondering why).

To avoid this:

package main

import "fmt"

const (
    one = 1 + iota
    two
    three
    four
)

const (
    zero = iota
)

func main() {
    fmt.Println(zero, one, two, three, four)
    // Output:
    // 0 1 2 3 4
}

... you should wrap each iota sequence in a separate const declaration like this.

脚注
  1. Strictly speaking, iota is not a counter. I have summarized this in my article "Writing properly about the iota constant generator" (Japanese text). ↩︎

GitHubで編集を提案

Discussion