Louis Thibault
Louis Thibault

Reputation: 21420

How can I iterate over a Decoder?

I come from a Python background and so have a tendency to think in terms of iterators. It seems to me that the range keyword in Go intends for us to think in a nearly identical way, so I would like to do somthing semantically equivalent to this Python code in Go:

for obj in json_decoder:
    # business logic

Here is the motivating case in Go; consider the following function:

func (c *GorpController) Create(dec *json.Decoder) {
    // business logic
}

I would like to be able to implement it as:

for someValue := range dec {
    // business logic
}

Is there some sort of way to use range with a Decoder interface? A function that wraps it in a different interface would be ideal, and an idiomatic pattern would be acceptable.

Thank you!

Upvotes: 1

Views: 806

Answers (2)

Dean Elbaz
Dean Elbaz

Reputation: 2450

Unfortunately, you can only use range with an "array, slice, string, or map, or reading from a channel" (see effective go)

to iterate over structs as they get decoded, the documentation recommends doing:

dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
    var m Message
    if err := dec.Decode(&m); err == io.EOF {
        break
    } else if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s: %s\n", m.Name, m.Text)
}

(taken directly from the official doc example)

Upvotes: 3

mna
mna

Reputation: 23973

A json.Decoder is a struct, and in Go, you can only iterate (use range) over strings, slices/arrays, maps and channels (https://golang.org/ref/spec#For_statements).

You can, however, loop over all JSON-encoded values in an io.Reader:

func main() {
    s := `"a string"
72
["an", "array"]
{"an": "object"}
`
    dec := json.NewDecoder(strings.NewReader(s))
    for {
        var v interface{}
        if err := dec.Decode(&v); err != nil {
            if err == io.EOF {
                break
            }
            log.Fatal(err)
        }
        log.Print(v)
    }
}

http://play.golang.org/p/flqXlcx_6B

EDIT: although More does seem to work for values as in this example, it is not its intended usage (based on the godoc), so checking for err == io.EOF would be better. Updated the code snippet.

Upvotes: 1

Related Questions