モジュールのレッスン (5/5)
`エンコーディング/json`
encoding/json は、Go 構造体を JSON にシリアル化したり、逆にシリアル化したりするための正規パッケージです。その規則と落とし穴を理解しておけば、API や構成ファイルのデバッグにかかる時間を節約できます。
マーシャルとアンマーシャル
2 つの主な機能:
data, err := json.Marshal(v) // Go → []byte JSON
err = json.Unmarshal(data, &v) // JSON → Go (pass a pointer!)type User struct {
Name string
Email string
}
u := User{Name: "Ada", Email: "ada@example.com"}
b, _ := json.Marshal(u)
fmt.Println(string(b))
// {"Name":"Ada","Email":"ada@example.com"}
var back User
_ = json.Unmarshal(b, &back)インデントされた出力 (人間が読める形式) の場合は、json.MarshalIndent(v, "", " ") を使用します。
エクスポートされたフィールドのみ
json.Marshal は、エクスポートされたフィールドのみ をシリアル化します (大文字)。プライベートフィールドは黙って無視されます:
type U struct {
Name string // exported → serialized
age int // private → ignored
}構造体タグ:名前とオプションの制御
json:"..." タグは、出力の名前、省略、タイプを制御します。
type User struct {
Name string `json:"name"` // rename
Email string `json:"email,omitempty"` // omit if zero value
Private string `json:"-"` // never serialized
ID int `json:"id,string"` // number as string
}最もよく使用されるオプション:
,omitempty— ゼロ値 (0、""、nil、空のスライス/マップ) の場合、フィールドを省略します。,-— シリアル化/逆シリアル化されません。,string— 数値/ブール値を文字列としてラップします (JS ID に便利)。
ストリームのデコーダ/エンコーダ
io.Reader/io.Writer (HTTP 本体、巨大なファイル) を操作する場合は、すべてをメモリにロードするのではなく、Decoder および Encoder を使用します。
dec := json.NewDecoder(resp.Body)
var users []User
if err := dec.Decode(&users); err != nil {
return err
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
_ = enc.Encode(users)Decoder は、ストリーミングの部分ごとの解析のための dec.Token() と、予期しないキーを含む JSON を拒否するための dec.DisallowUnknownFields() (入力検証に役立ちます) もサポートしています。
汎用マップと any
スキーマがわからない場合は、map[string]any に逆シリアル化します。
var v map[string]any
_ = json.Unmarshal(data, &v)
fmt.Println(v["name"])値には動的タイプが含まれます (数値の場合は string、float64、[]any、map[string]any、bool、nil)。
よくあるエラー
&を忘れると、json.Unmarshal(data, v)には何も入力されません。&vが必要です。- nil フィールドを含む構造体のデコード: パニックを避けるために、フィールドを読み取る前に
errを確認してください。 - 互換性のない型: 数値を文字列に逆シリアル化すると、
*json.UnmarshalTypeErrorが返されます。
演習
json.Marshal を使用して struct u を JSON にシリアル化し、結果を文字列として出力します。
3 回の試行後に解決策が利用可能になります
json.Unmarshal を使用して `{"Name":"Ada"}` を構造体 U に逆シリアル化して出力します。
3 回の試行後に解決策が利用可能になります
構造体のフィールド `name string` (小文字) は json.Marshal に含まれていますか?
type U struct {
name string
}
b, _ := json.Marshal(U{name: "Ada"})
fmt.Println(string(b))