這段程式碼實現了一個簡單的 JSON 序列化和反序列化功能。程式碼包括一個 User
結構體和兩個函式 Marshal
和 UnMarshal
,分別用於將資料轉換為 JSON 格式和將 JSON 格式的資料解析回結構體。
package main
import (
"bytes"
"fmt"
"reflect"
"strconv"
"strings"
)
// User 定義了一個使用者結構體,其中包含名稱、年齡和性別欄位
type User struct {
Name string
Age string
Sex byte `json:"gender"` // 使用 json 標籤自定義欄位名
}
// Marshal 將任意型別 v 序列化為 JSON 格式的位元組陣列
func Marshal(v interface{}) ([]byte, error) {
value := reflect.ValueOf(v) // 獲取值的反射物件
typ := value.Type() // 獲取值的型別
bf := bytes.Buffer{} // 使用 bytes.Buffer 以高效地構造 JSON 字串
switch typ.Kind() {
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int8, reflect.Int64, reflect.Uint8:
// 對於整數型別,將其轉換為字串並返回位元組陣列
return []byte(fmt.Sprintf("%v", value.Interface())), nil
case reflect.String:
// 對於字串型別,將其加上雙引號後返回位元組陣列
return []byte("\"" + value.String() + "\""), nil
case reflect.Bool:
// 對於布林值,將其轉換為 "true" 或 "false" 字串
return []byte(fmt.Sprintf("%t", value.Bool())), nil
case reflect.Float32, reflect.Float64:
// 對於浮點數型別,將其轉換為字串並返回位元組陣列
return []byte(fmt.Sprintf("%f", value.Float())), nil
case reflect.Struct:
// 對於結構體型別,構造 JSON 格式的字串
bf.WriteByte('{')
if value.NumField() > 0 {
for i := 0; i < value.NumField(); i++ {
fieldValue := value.Field(i) // 獲取欄位值
fieldType := typ.Field(i) // 獲取欄位型別
if fieldType.IsExported() {
// 處理匯出欄位
name := fieldType.Name
if len(fieldType.Tag.Get("json")) > 0 {
// 使用 JSON 標籤指定的欄位名
name = fieldType.Tag.Get("json")
}
bf.WriteByte('"')
bf.WriteString(name)
bf.WriteByte('"')
bf.WriteByte(':')
if bs, err := Marshal(fieldValue.Interface()); err == nil {
bf.Write(bs)
} else {
return nil, err
}
bf.WriteByte(',')
}
}
bf.Truncate(len(bf.Bytes()) - 1) // 刪除最後一個逗號
}
bf.WriteByte('}')
return bf.Bytes(), nil
default:
// 對於不支援的型別,返回錯誤
return nil, fmt.Errorf("暫不支援該型別%s", typ.Kind())
}
}
// UnMarshal 將 JSON 格式的位元組陣列 data 解析為型別為 v 的值
func UnMarshal(v interface{}, data []byte) error {
value := reflect.ValueOf(v) // 獲取值的反射物件
typ := value.Type() // 獲取值的型別
if typ.Kind() != reflect.Ptr {
return fmt.Errorf("必須為指標")
} else {
typ = typ.Elem() // 獲取指標指向的型別
value = value.Elem() // 獲取指標指向的值
}
s := string(data) // 將位元組陣列轉換為字串
switch typ.Kind() {
case reflect.Int:
// 解析整數
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
value.SetInt(i) // 設定解析後的整數值
} else {
return err
}
case reflect.Uint8:
// 解析無符號整數(位元組)
if i, err := strconv.ParseUint(s, 10, 64); err == nil {
value.SetUint(i) // 設定解析後的位元組值
} else {
return err
}
case reflect.Bool:
// 解析布林值
if b, err := strconv.ParseBool(s); err == nil {
value.SetBool(b) // 設定解析後的布林值
} else {
return err
}
case reflect.Float32:
// 解析浮點數
if f, err := strconv.ParseFloat(s, 64); err == nil {
value.SetFloat(f) // 設定解析後的浮點數值
} else {
return err
}
case reflect.String:
// 解析字串,確保字串被雙引號包圍
if s[0] == '"' && s[len(s)-1] == '"' {
value.SetString(s[1 : len(s)-1]) // 去掉雙引號
} else {
return fmt.Errorf("json格式不對")
}
case reflect.Struct:
// 解析結構體
if s[0] == '{' && s[len(s)-1] == '}' {
arr := strings.Split(s[1:len(s)-1], ",") // 去掉大括號並拆分欄位
if len(arr) > 0 {
fieldCount := typ.NumField()
tag2Field := make(map[string]string, fieldCount)
for i := 0; i < fieldCount; i++ {
fieldType := typ.Field(i)
name := fieldType.Name
if len(fieldType.Tag.Get("json")) > 0 {
// 使用 JSON 標籤指定的欄位名
name = fieldType.Tag.Get("json")
}
tag2Field[name] = fieldType.Name
}
for _, ele := range arr {
brr := strings.SplitN(ele, ":", 2) // 拆分標籤和資料
tag := brr[0]
if tag[0] == '"' && tag[len(tag)-1] == '"' {
tag = tag[1 : len(tag)-1]
if fieldName, exists := tag2Field[tag]; exists {
fieldValue := value.FieldByName(fieldName)
fieldType := fieldValue.Type()
if fieldValue.Kind() != reflect.Ptr {
fieldValue = fieldValue.Addr()
if err := UnMarshal(fieldValue.Interface(), []byte(brr[1])); err != nil {
return err
}
} else {
newValue := reflect.New(fieldType.Elem())
if err := UnMarshal(newValue.Interface(), []byte(brr[1])); err != nil {
return err
} else {
fieldValue.Set(newValue)
}
}
}
} else {
return fmt.Errorf("json格式不對%s", tag)
}
}
}
} else {
return fmt.Errorf("格式錯誤")
}
default:
// 對於不支援的型別,返回錯誤
return fmt.Errorf("暫不支援該資料型別%s", typ.Kind())
}
return nil
}
// main 函式演示瞭如何使用 Marshal 和 UnMarshal 函式
func main() {
user := User{
Name: "ffff5",
Age: "35",
Sex: 1,
}
if date, err := Marshal(user); err == nil {
fmt.Println(string(date)) // 列印序列化後的 JSON 字串
var u2 = user
if err := UnMarshal(&u2, date); err == nil {
fmt.Println(u2.Name, u2.Age, u2.Sex) // 列印反序列化後的資料
} else {
fmt.Println(err) // 列印錯誤資訊
}
} else {
fmt.Println(err) // 列印序列化錯誤
}
}
-
User
結構體:- 定義了一個包含
Name
(名稱)、Age
(年齡)和Sex
(性別)欄位的結構體。 Sex
欄位使用了json
標籤來指定 JSON 中的欄位名為"gender"
。
- 定義了一個包含
-
Marshal
函式:- 將傳入的任意型別的值轉換為 JSON 格式的位元組陣列。
- 支援整數、字串、布林值、浮點數和結構體。
- 對於結構體,處理欄位標籤和序列化欄位值。
-
UnMarshal
函式:- 將 JSON 格式的位元組陣列解析為傳入指標型別
v
所指向的值。 - 支援整數、位元組(無符號 8 位整數)、布林值、浮點數、字串和結構體。
- 處理 JSON 格式,支援透過標籤來解析結構體欄位。
- 將 JSON 格式的位元組陣列解析為傳入指標型別
-
main
函式:- 建立一個
User
物件,並將其序列化為 JSON。 - 將序列化後的 JSON 字串反序列化為新的
User
物件,並列印結果。
- 建立一個