ข้ามไปยังเนื้อหา

encoding/json

Package encoding/json แปลงค่า Go เป็น JSON text (marshaling) และแปลง JSON text กลับเป็นค่า Go (unmarshaling) ฟังก์ชันหลักสองตัวคือ:

data, err := json.Marshal(v) // Go value → []byte (JSON)
err = json.Unmarshal(data, &v) // []byte (JSON) → Go value

Marshal รับค่าใดก็ได้และคืน []byte Unmarshal เขียนลงในค่าที่ชี้โดย argument ที่สอง — ส่ง pointer เสมอเพื่อให้ฟังก์ชันแก้ไขตัวแปรได้

Struct tag คือ raw-string literal บน field ของ struct ที่ให้ metadata Package encoding/json อ่าน tag json:"name" เพื่อควบคุมการ serialize:

type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Age int `json:"age"`
}

syntax ของ tag คือ `json:"<name>[,options]"` option ที่พบบ่อย:

Tagผล
json:"name"ใช้ name เป็น JSON key แทนชื่อ field
json:"name,omitempty"ละเว้น field นี้ใน output เมื่อค่าเป็น zero value
json:"-"ละเว้น field นี้เสมอ

Field ของ struct สามารถเป็น struct ได้เช่นกัน json.Marshal จะ recurse เข้าไปโดยอัตโนมัติ:

type Address struct {
City string `json:"city"`
Country string `json:"country"`
}
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
}

JSON ที่ได้จะฝัง address object ไว้ภายใต้ key "address"

เมื่อยังไม่มี struct type ล่วงหน้า ให้ unmarshal ลงใน map[string]any แต่ละค่า JSON จะกลายเป็น Go counterpart ที่เป็นธรรมชาติ: string, float64, bool, []any, map[string]any หรือ nil

var m map[string]any
json.Unmarshal([]byte(`{"lang":"Go","version":1.22}`), &m)
fmt.Println(m["lang"]) // Go
fmt.Println(m["version"]) // 1.22 (float64)
package main
import (
"encoding/json"
"fmt"
)
type Address struct {
City string `json:"city"`
Country string `json:"country"`
}
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"`
Address Address `json:"address"`
}
func main() {
// Marshal a struct — Email is set, so it appears
u := User{
Name: "Alice",
Age: 30,
Address: Address{
City: "Bangkok",
Country: "Thailand",
},
}
data, err := json.Marshal(u)
if err != nil {
fmt.Println("marshal error:", err)
return
}
fmt.Println(string(data))
// omitempty: Email is empty, so it is omitted
u2 := User{Name: "Bob", Age: 25, Address: Address{City: "London", Country: "UK"}}
data2, _ := json.Marshal(u2)
fmt.Println(string(data2))
// Unmarshal back into a struct
var result User
err = json.Unmarshal(data, &result)
if err != nil {
fmt.Println("unmarshal error:", err)
return
}
fmt.Printf("Name: %s, City: %s\n", result.Name, result.Address.City)
// map[string]any — flexible unmarshaling
raw := `{"lang":"Go","version":1.22,"stable":true}`
var m map[string]any
_ = json.Unmarshal([]byte(raw), &m)
fmt.Println(m["lang"], m["version"], m["stable"])
}
สิ่งที่ได้ประโยชน์ต้นทุน
json.Marshal/Unmarshalง่าย, ไม่ต้อง schemareflect-based — ช้ากว่า code-gen 2-5x
struct tags (json:“name”)control field names, omitemptyruntime-only — ไม่มี compile-time check ว่า tag ถูกต้อง
json.Decoder (streaming)decode large/stream JSON โดยไม่ load ทั้งหมดใน memoryAPI ซับซ้อนกว่า Unmarshal
omitemptyไม่ส่ง zero value ใน JSON0, false, "" ถือเป็น empty — อาจ surprise
  • json.Marshal/Unmarshal thread-safe — ใช่ — แต่ json.Decoder/Encoder แต่ละ instance ไม่ thread-safe อย่าแชร์ข้าม goroutine
  • unexported field ถูก marshal — ไม่ — unexported field ถูก ignore โดย encoding/json ไม่ว่าจะมี tag หรือไม่
  • omitempty ทำงานกับ pointer เหมือน value — omitempty บน *T: nil → omit, non-nil → include แม้ว่า value ข้างใน pointer เป็น zero
  • interface{} field ใน struct marshal เป็น null เสมอ — marshal ตาม concrete type ที่ store อยู่ใน interface ตอน runtime

💡 ตัวอย่างจากของจริง

Kubernetes API: ทุก Kubernetes resource (Pod, Deployment, Service) marshal/unmarshal ผ่าน encoding/json — struct tags ควบคุม JSON key ทั้งหมด

Go REST API: json.NewDecoder(r.Body).Decode(&req) คือ pattern มาตรฐานที่ทุก Go API server ใช้สำหรับ parse request body

Prometheus: /metrics endpoint ใช้ custom text format แต่ HTTP config และ rule file ใช้ json.Unmarshal สำหรับ admin API

json.Unmarshal ต้องการอะไรเป็น argument ที่สอง?
Field ของ struct ที่มี tag `json:"email,omitempty"` และมีค่าเป็น empty string จะ:
เมื่อ unmarshal JSON ลงใน map[string]any ตัวเลข 1.22 จะกลายเป็น type ใดของ Go?
Field ของ struct ชื่อ userID (u พิมพ์เล็ก) ที่มี tag json:"user_id" จะ: