dP            dP                d8888b. .d888b. d8             dP       dP                   
  88            88                    `88 Y8' `8P 88             88       88                   
d8888P dP    dP 88d888b. .d8888b. .aaadP' d8bad8b .P .d8888b.    88d888b. 88 .d8888b. .d8888b. 
  88   88    88 88'  `88 88'  `88 88'     88` `88    Y8ooooo.    88'  `88 88 88'  `88 88'  `88 
  88   88.  .88 88.  .88 88.  .88 88.     8b. .88          88    88.  .88 88 88.  .88 88.  .88 
  dP   `88888P' 88Y8888' `88888P' Y88888P Y88888P    `88888P'    88Y8888' dP `88888P' `8888P88 
                                                                                           .88 
                                                                                       d8888P
つぼのブログ

json.Encoder は出力の末尾に改行をつける

| tech go

json.Marshal と json.Encoder の微妙な違い

json.Encoder は生成した JSON の末尾に改行を追加します。json.Marshal は追加しません。

以下のコードと出力の通りです。スライスの末尾の 10 に注目。

package main

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

func main() {
	m := map[string]string{
		"hello": "world",
	}

	fmt.Println("json.Encoder")
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(m)
	fmt.Println("========")
	fmt.Printf("%s\n", b.Bytes())
	fmt.Println("========")
	fmt.Printf("%v\n", b.Bytes())
	fmt.Println("")

	fmt.Println("json.Marshal")
	buf, _ := json.Marshal(m)
	fmt.Println("========" )
	fmt.Printf("%s\n", buf)
	fmt.Println("========")
	fmt.Printf("%v\n", buf)
}
json.Encoder
========
{"hello":"world"}

========
[123 34 104 101 108 108 111 34 58 34 119 111 114 108 100 34 125 10]

json.Marshal
========
{"hello":"world"}
========
[123 34 104 101 108 108 111 34 58 34 119 111 114 108 100 34 125]

どちらも JSON として合法なので、Web API のレスポンスなどとして使う際は問題ありません。

しかし、例えば json.Marshal を使っている関数のテストで、期待する出力を json.Encoder で作ってしまうと微妙にハマるかもしれません。私はハマりました。

理由

json.Encoderio.Writer を引数に取り、TCP ソケットやファイルなどに何度でも書き込める設計です。参考文献の Stack Overflow によると、区切りの改行があると見やすく、また一つの JSON の終わりを改行によって判定できるようになることが理由らしいです。

まぁそうですね。

参考文献