5

json.Encoder一度にすべてのデータをメモリにロードせずに、大量のデータ ストリームをエンコードするために使用したいと考えています。

// I want to marshal this
t := struct {
    Foo string

    // Bar is a stream of objects 
    // I don't want it all to be in memory at the same time.
    Bar chan string 
}{
    Foo: "Hello World",
    Bar: make(chan string),
}

// long stream of data
go func() {
    for _, x := range []string{"one", "two", "three"} {
        t.Bar <- x
    }
    close(t.Bar)
}()

おそらくjsonパッケージにこの機能が組み込まれているのではないかと思いましたが、そうではありません。

遊び場

// error: json: unsupported type: chan string
if err := json.NewEncoder(os.Stdout).Encode(&t); err != nil {
    log.Fatal(err)
}

私は現在、json文字列を自分で構築しています。

遊び場

w := os.Stdout
w.WriteString(`{ "Foo": "` + t.Foo + `", "Bar": [`)

for x := range t.Bar {
    _ = json.NewEncoder(w).Encode(x)
    w.WriteString(`,`)
}

w.WriteString(`]}`)

これを行うより良い方法はありますか?

json.Marshalerがこのようなものであった場合、それは些細なことです。

type Marshaler interface {
    MarshalJSON(io.Writer) error
}
4

2 に答える 2

2

残念ながら、encoding/jsonパッケージにはまだこれを行う方法がありません。組み込みパッケージを変更せずに、現在 (手動で) 行っていることが最善の方法です。

にパッチを当てる場合は、 encoding/json/encode.goの関数をencoding/json変更できます。reflectValueQuoted

配列のケースに注目したいでしょう (Slice には がありますfallthrough):

// Inside switch:
case reflect.Array:
    e.WriteByte('[')
    n := v.Len()
    for i := 0; i < n; i++ {
        if i > 0 {
            e.WriteByte(',')
        }
        e.reflectValue(v.Index(i))
    }
    e.WriteByte(']')

チャンネルも同じように扱いたいと思います。次のようになります。

// Inside switch:
case reflect.Chan:
    e.WriteByte('[')
    i := 0
    for {
        x, ok := v.Recv()
        if !ok {
            break
        }
        if i > 0 {
            e.WriteByte(',')
        }
        e.reflectValue(x)
        i++
    }
    e.WriteByte(']')

私は のチャンネルをあまり扱っていないreflectので、上記は他のチェックが必要かもしれません。

このルートをたどる場合は、いつでもパッチを送信できます。

于 2013-08-08T20:32:31.323 に答える