文章目錄
- 1. 寫在最前面
- 2. 字段區分出空字段還是未設置字段
- 2.1 問題描述
- 2.2 解決
- 3. 字段支持多種類型 & 按需做不同類型處理
- 3.1 問題描述
- 3.2 解決
- 4. 碎碎念
- 5. 參考資料
1. 寫在最前面
筆者最近在實現將內部通知系統的數據定義轉化為產品定義的對外提供的數據結構。
-
舉例說明內部系統數據定義返回的結構定義有如下幾種:
-
{"magName": "uploader", "status": 0}
-
{"magName": "uploaded", "fileList": ["testa", "testb"]}
-
{"magName": "upload_start", "fileList": "test"}
-
{"magName": "uploading", "progress": 1000}
-
在將如上數據結構轉換的時候有兩種思路
-
內部通知系統的數據結構 1:1 跟產品外部定義結構進行映射
-
內部通知系統的數據結構 n:1 跟產品外部定義的結構進行映射
在進一步拆解問題,在做 n:1 映射的時候,需要解決的是如何定義一個通用的產品定義結構,能夠按需根據產品定義進行進行映射。該結構需要解決如下兩件事情:
-
fileList 字段:可以設置兩種不同類型,并且支持對改不同類型的返回進行補充
-
status 字段:可以區分出空字段還是未設置字段
2. 字段區分出空字段還是未設置字段
2.1 問題描述
在配置了 omitempty
tag 的字段設置的值為默認值時,對該字段做 marshal 的時候,該字段會被忽略。
例子:
package mainimport ("encoding/json""fmt"
)type Message struct {Status int `json:"status,omitempty"`MsgName string `json:"msgName,omitempty"`
}func main() {//1. status 為默認值 0 時,做 unmarshal 可以解析出該字段test := `{"status": 0, "msgName": "hello"}`var m Messageerr := json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}fmt.Printf("%v\n", m)//2. status 為默認值 0 時,做 marshal 時不會輸出該字段data, err := json.Marshal(m)if err != nil {fmt.Println(err)}fmt.Printf("%s\n", data)
}
輸出:
$> go run main.go
unmarshal: {0 hello}
marshal: {"msgName":"hello"}
2.2 解決
將可能為默認值的字段設置為指針類型,比如 int
設置為 *int
package mainimport ("encoding/json""fmt"
)type Message struct {Status *int `json:"status,omitempty"`MsgName string `json:"msgName,omitempty"`
}func main() {//1. status 為默認值 0 時,做 unmarshal 可以解析出該字段test := `{"status": 0, "msgName": "hello"}`var m Messageerr := json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}fmt.Printf("unmarshal: %v\n", m)//2. status 為默認值 0 時,做 marshal 會輸出該字段data, err := json.Marshal(m)if err != nil {fmt.Println(err)}fmt.Printf("marshal: %s\n", data)
}
輸出:
$> go run main.go
unmarshal: {0x14000110108 hello}
marshal: {"status":0,"msgName":"hello"}
注:設置了指針類型的字段,如果原始的字段不存在時,則結構體字段為空(nil)
3. 字段支持多種類型 & 按需做不同類型處理
3.1 問題描述
某個指定字段支持配置兩種類型,同時需要不同類型做產品指定的加工處理。
package mainimport ("encoding/json""fmt"
)type Message struct {Status *int `json:"status,omitempty"`MsgName string `json:"msgName,omitempty"`FileList any `json:"fileList,omitempty"`
}func fixFileList(fileList any) any {switch fileList.(type) {case string:fileList = fmt.Sprintf("string type [%s]", fileList.(string))return fileListfmt.Printf("fileList: %v\n", fileList)case []interface{}:fileListArr := fileList.([]interface{})for i, _ := range fileListArr {fileListArr[i] = fmt.Sprintf("array type [%s]", fileListArr[i])}return fileListArr}return "unknown"
}func main() {//1. FileList 字段為 string 類型test := `{"status": 0, "msgName": "hello", "fileList": "world"}`var m Messageerr := json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}m.FileList = fixFileList(m.FileList)fmt.Printf("unmarshal 1: %v\n", m)//2. FileList 字段為 array 類型test = `{"status": 0, "msgName": "hello", "fileList": ["world", "world2"]}`err = json.Unmarshal([]byte(test), &m)if err != nil {fmt.Println(err)}m.FileList = fixFileList(m.FileList)fmt.Printf("unmarshal 2: %v\n", m)}
輸出:
$> go run main.go
unmarshal 1: {0x1400000e220 hello string type [world]}
unmarshal 2: {0x1400000e220 hello [array type [world] array type [world2]]}
3.2 解決
解決方案分為兩個步驟:
-
將該字段設置為 any 或者 insterface 類型
-
然后在根據斷言的類型不同做不同的產品展示結果補充
4. 碎碎念
以上就是關于某次處理臟業務邏輯的包裝記錄,本來還打算把晚上學到的 json inline
用法記錄說明一下,但是由于本人還沒有實踐過,那就后面用的時候在繼續記錄吧。
-
18歲很好,28歲也不錯,38歲可能會更好,只要皺紋不長進心里,我們就永遠風華正茂。
-
一個女人最重要的能力,不是你把自己打扮得多么漂亮,也不是你掙錢有多厲害,而是無論發生任何事情,你都有快樂起來的能力。
-
當你越來越優秀時,你開始明白,其實每個人都沒有好壞之分,沒有對錯,只有頻率不同,做出了不同的選擇。有個好心態,路就會走的更寬。
5. 參考資料
-
Golang 的 “omitempty” 關鍵字略解
-
Golang 中使用 JSON 時如何區分空字段和未設置字段?