Reputation: 21420
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
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
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