minio / simdjson-go

Golang port of simdjson: parsing gigabytes of JSON per second
Apache License 2.0
1.8k stars 85 forks source link

foreach example in document is incorrect #61

Closed flowchartsman closed 2 years ago

flowchartsman commented 2 years ago

given the following main.go:

package main

import (
    "fmt"
    "log"

    "github.com/minio/simdjson-go"
)

func main() {
    // Parse JSON:
    pj, err := simdjson.Parse([]byte(`{"Image":{"URL":"http://example.com/example.gif"}}`), nil)
    if err != nil {
        log.Fatal(err)
    }

    // Iterate each top level element.
    _ = pj.ForEach(func(i simdjson.Iter) error {
        fmt.Println("Got iterator for type:", i.Type())
        element, err := i.FindElement(element, "Image", "URL")
        if err == nil {
            value, _ := element.Iter.StringCvt()
            fmt.Println("Found element:", element.Name, "Type:", element.Type, "Value:", value)
        }
        return nil
    })

    // Output:
    // Got iterator for type: object
    // Found element: URL Type: string Value: http://example.com/example.gif
}

The following error is produced:

./main.go:20:33: undefined: element

Presumably, the user needs to initialize a (reusable?) *simdjson.Element, but this is not mentioned and the documentation for *Iter.FindElement does not provide any guidance on *simdjson.Element reuse. Could this be clarified? Is it safe to call *iter.FindElement multiple times to manually extract values into a struct? Further if WithCopyStrings(false) is set, is it okay to use these values, provided they are copied?

klauspost commented 2 years ago

For the example, it can just be nil. Yes, you are free to reuse whatever *Element you aren't using anymore.

klauspost commented 2 years ago

A safe example with reuse would look like this:

package main

import (
    "fmt"
    "log"

    "github.com/minio/simdjson-go"
)

func main() {
    // Parse JSON:
    pj, err := simdjson.Parse([]byte(`{"Image":{"URL":"http://example.com/example.gif"}}`), nil)
    if err != nil {
        log.Fatal(err)
    }

    // Iterate each top level element.
    var element *simdjson.Element
    _ = pj.ForEach(func(i simdjson.Iter) error {
        fmt.Println("Got iterator for type:", i.Type())
        var err error
        element, err = i.FindElement(element, "Image", "URL")
        if err == nil {
            value, _ := element.Iter.StringCvt()
            fmt.Println("Found element:", element.Name, "Type:", element.Type, "Value:", value)
        }
        return nil
    })

    // Output:
    // Got iterator for type: object
    // Found element: URL Type: string Value: http://example.com/example.gif
}