前言
在前端處理傳遞資料到後端時都快忘了有「序列化與反序列化資料」這個步驟,因為都被套件像是:Axios 抽象掉了,近期在寫後端也重新溫習相關知識,也延續先前文章:Go Struct Tag 是什麼?如何透過 reflect 動態處理欄位? 探討 Go 如何處理序列化資料。
fetch("x", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data)})
// Axios 自動序列化資料axios.post("x", { project_id: "<project_id>"})序列化與編組
什麼是序列化 Serialization?
程式語言有自己的資料結構,像是 Go 的 map 與 JavaScript 的 object 雖然外表相似但背後實踐卻完全不同,為了讓兩者相互溝通最常見就是透過 JSON 資料格式來傳遞資料。
把記憶體中的資料結構轉換成可儲存或可傳輸的格式稱為序列化(Serialization),再將其還原回原始資料結構稱為反序列化(Deserialization)。
什麼是編組 Marshal
Marshal 原意是「集結」、「編排」或「整理」。
- 軍事: “To marshal troops”(集結部隊),代表將零散的士兵排列成有序的陣型,以便行動。
- 法律或活動: “To marshal facts”(整理事實),代表將混亂的資訊整理成有邏輯的結構。
- 電腦科學:被借喻為將記憶體中「散落」或「指標導向」的複雜資料結構(如一個含有指標的 Struct),整隊排列成一串可以傳輸的扁平(Flat)位元組。
Marshal 與 Serialization 的微小差異
雖然大多數情況下它們可以互換,但在電腦科學的術語定義上,兩者存在細微差別:
| 特性 | Serialization (序列化) | Marshalling (編組) |
|---|---|---|
| 核心意圖 | 將資料轉換為持久化格式(存檔、存資料庫)。 | 將資料轉換為傳輸格式(跨程序或跨網路通訊)。 |
| 包含內容 | 通常只關注資料數值本身。 | 除了資料,有時還包含元數據(Metadata),甚至涉及遠端過程調用(RPC)的處理。 |
| 結構複雜度 | 側重於線性化。 | 側重於將複雜、非連續的物件「整隊」成可傳輸的形式。 |
Go Marshal
Go 標準庫已經內建 encoding/json 套件。
- Struct 欄位名稱會直接成為 JSON key
- 大寫開頭的欄位才能被序列化(exported)
import ( "encoding/json" "fmt")
type User struct { Name string Email string}
u := User{ Name: "Riceball",}
b, err := json.Marshal(u)if err != nil { log.Fatal(err)}JSON struct tag
通常會透過 struct tag 來控制輸出格式:
type User struct { Name string `json:"name"` Email string `json:"email"`}
// 轉換出 JSON 格式:{"name":"Riceball","email":"[email protected]"}type User struct { ID int `json:"id"` // 重新命名欄位 Name string `json:"name,omitempty"` // 零值時不輸出 Token string `json:"-"` // 完全忽略此欄位} type User struct { ID int `json:"id"` Name string `json:"name,omitempty"` Token string `json:"-"` }
var u User if err != nil { fmt.Println("出錯了:", err) } fmt.Printf("解析結果: %+v\n", u) // 解析結果: {ID:0 Name:Riceball Token:}延伸閱讀
- What does Go’s JSON package mean when it refers to Marshal? [closed] - stack overflow
- What is the difference between Serialization and Marshaling? - stack overflow
- Go by Example: JSON