LoginSignup
1
1

Go言語でのJSON操作: json.Marshal, json.Unmarshal, json.NewDecoder, json.NewEncoderの使い分け

Last updated at Posted at 2023-06-11

はじめに

Go言語の学習中に、JSONを扱うのにencoding/jsonパッケージのjson.Marshal, json.Unmarshal,json.NewDecoder,json.NewEncoderといった関数を使うけど、これらの関数の使い分けについて気になりました。そこで、この記事ではそれぞれの関数の特性と適した使用場面について学んだことを記述しています。

json.Marshal, json.Unmarshalについて

まず、json.Marshaljson.Unmarshalですが、これらの関数は主にメモリ内のデータをJSON形式にシリアライズ(変換)したり、JSONをデシリアライズ(変換)してデータを読み出したりするのに使用されます。以下にその使用例を示します。

json.Marshalの使用例

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    p := Person{Name: "Alice", Age: 20}
    fmt.Println(p)
    // 出力: {Alice 20}

    bytes, err := json.Marshal(p)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(bytes)
    // 出力: [123 34 78 97 109 101 34 58 34 65 108 105 99 101 34 44 34 65 103 101 34 58 50 48 125]
    // これはJSON形式の文字列をASCIIコードに対応する整数のスライスとして表現したものです。

    fmt.Println(string(bytes))
    // 出力: {"Name":"Alice","Age":20}
}

json.Unmarshalの使用例

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    jsonBytes := []byte(`{"Name":"Alice","Age":20}`)
    fmt.Println(jsonBytes)
    // 出力: [123 34 78 97 109 101 34 58 34 65 108 105 99 101 34 44 34 65 103 101 34 58 50 48 125]
    // これはJSON形式の文字列をASCIIコードに対応する整数のスライスとして表現したものです。

    fmt.Println(string(jsonBytes))
    // 出力: {"Name":"Alice","Age":20}

    var p Person
    err := json.Unmarshal(jsonBytes, &p)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(p)
    // 出力: {Alice 20}
}

json.NewDecoder, json.NewEncoderについて

次に、json.NewDecoderjson.NewEncoderです。これらの関数はストリーム形式のデータを扱う際に使用します。例えば、ネットワーク経由で送受信するデータや、大きなファイルから読み出すデータなどです。以下にその使用例を示します。

json.NewDecoder

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    jsonReader := strings.NewReader(`{"Name":"Alice","Age":20}`)
    fmt.Printf("%#v\n", jsonReader)
    // 出力: &strings.Reader{...} 
    // jsonReaderはstrings.Readerの構造体のポインタであり、内部的な状態を表現するフィールドを含んでいます。

    jsonDecoder := json.NewDecoder(jsonReader)
    fmt.Printf("%#v\n", jsonDecoder)
    // 出力: &json.Decoder{...} 
    // jsonDecoderはjson.Decoderの構造体のポインタであり、内部的な状態を表現するフィールドを含んでいます。

    var p Person
    err := jsonDecoder.Decode(&p)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(p)
    // 出力: {Alice 20}
}

json.NewEncoder

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    p := Person{Name: "Alice", Age: 20}
    fmt.Printf("%#v\n", p)
    // 出力: main.Person{Name:"Alice", Age:20}

    buffer := &bytes.Buffer{}
    fmt.Printf("%#v\n", buffer)
    // 出力: &bytes.Buffer{...} 
    // bufferはbytes.Bufferの構造体のポインタであり、内部的な状態を表現するフィールドを含んでいます。

    jsonEncoder := json.NewEncoder(buffer)
    fmt.Printf("%#v\n", jsonEncoder)
    // 出力: &json.Encoder{...} 
    // jsonEncoderはjson.Encoderの構造体のポインタであり、内部的な状態を表現するフィールドを含んでいます。

    err := jsonEncoder.Encode(p)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(buffer.String())
    // 出力: {"Name":"Alice","Age":20}
}

両者の比較

json.Marshaljson.Unmarshalは一度に全てのデータをメモリにロードし、その全てをJSON形式にシリアライズ、またはJSON形式からデシリアライズします。一方、json.NewEncoderjson.NewDecoderはストリーム形式のデータを扱います。つまり、データは順次読み込まれ、必要に応じてエンコードまたはデコードされます。この特性から、大量のデータを扱う際や、ネットワーク経由でデータを送受信する際には、json.NewEncoderjson.NewDecoderを使うべきです。

一方で、メモリに十分に収まる量のデータを扱う際や、簡潔さが求められる場合には、json.Marshaljson.Unmarshalを用いると良いでしょう。

さいごに

以上、json.Marshal, json.Unmarshal, json.NewDecoder, json.NewEncoderの使い分けについて解説しました。それぞれの関数がどのようなシチュエーションで最適であるかを理解することで、より効率的なコーディングが可能になります。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1