🚢
【Go言語】もう迷わない!JSONの「エンコード・デコード(Marshal・Unmarshal)」の違いと覚え方
はじめに
Go言語でAPI開発などをしていると必ず遭遇するのが、JSONの変換処理です。
「Marshalってどっちだっけ?」「デコードはどっち向き?」と、毎回調べてしまう方も多いのではないでしょうか。
今回は、この「どっちがどっち問題」を視覚的に整理して解説します。
結論:方向で見れば一発!
一番大切なのは、「Goの世界」を基準に、データがどこへ向かっているかを考えることです。
| 操作 | 関数 | 方向 |
|---|---|---|
| エンコード(Marshal) | json.Marshal() |
Goの構造体 → JSONデータ |
| デコード(Unmarshal) | json.Unmarshal() |
JSONデータ → Goの構造体 |
- エンコード:Goで扱っているデータを、外部へ「出荷(パッキング)」するイメージ
- デコード:外部から届いたデータ(パズル)を、Goの枠組みに「はめ込む」イメージ
覚え方のコツ:単語のイメージ
英語の意味で紐付けると、より記憶に定着しやすくなります。
| 用語 | 英語のイメージ | Goでの動き |
|---|---|---|
| Marshal | (軍隊などを)整列させる | バラバラのデータを1行のJSONに整列させる |
| Unmarshal | 整列を解く | 1行のデータをバラして、構造体の各項目に配置し直す |
ヒント:「Marshal=整列=外に出せる綺麗な形にする」と覚えるとスムーズです!
コードで比較
実際にどのように使い分けるか、コードの形を見比べてみましょう。
エンコードの場合
「Goのデータ」を引数に渡すと、「JSON」が返ってきます。
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
user := User{Name: "Alice", Age: 30}
// 構造体 → JSON(バイト列)
jsonData, err := json.Marshal(user)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(jsonData)) // {"name":"Alice","age":30}
デコードの場合
「JSON」と「空の入れ物(ポインタ)」を渡して、中身を満たしてもらいます。
jsonData := []byte(`{"name":"Alice","age":30}`)
var u User
// JSON → 構造体(&u に中身が入る)
err := json.Unmarshal(jsonData, &u)
if err != nil {
log.Fatal(err)
}
fmt.Println(u.Name) // Alice
fmt.Println(u.Age) // 30
ポイント:なぜ Unmarshal にはポインタを渡すのか?
json.Unmarshal の第2引数には &u のようにポインタを渡す必要があります。これは、関数の内部でデコードした値を変数に書き込むためです。ポインタを渡さないと、関数の外に変更が反映されません。
まとめ
| エンコード | デコード | |
|---|---|---|
| 関数 | json.Marshal() |
json.Unmarshal() |
| データの流れ | Goの構造体 → JSON | JSON → Goの構造体 |
| イメージ | 荷物を箱に詰めて出荷 | 届いた箱を開けて中身を取り出す |
| 第2引数 | なし(戻り値でJSONを受け取る) | ポインタ(&u)を渡す |
- Goから外へ出すなら Encode(Marshal)
- 外からGoへ取り込むなら Decode(Unmarshal)
これで次からは迷わずに実装できるはずです。
Discussion