go语言序列化及反序列化

时间:2025-03-08 11:41:43

参考文章:
go 官方package: /json
特别好的文章:理解 Go 中的 JSON

JSON是一种轻量级的数据交换格式,常用在前后端数据交换,go的 encoding/json 提供了对json的支持

一、序列化

GO提供了 Marshal 方法:Go Struct转换为JSON对象,函数签名:

func Marshal(v interface{}) ([]byte, error)

举例:

type Person struct {
	Name   string
	Gender string
	Age    uint32
}

	// 默认初始化
	p := Person{"a", "male", 23}
	fmt.Println(p)
	fmt.Printf("%v\n", p) //{a male 23}

	// 指定成员初始化
	p1 := Person{Name: "wsq", Gender: "male"}
	fmt.Println(p1) //{wsq male 0}

	// 序列化
	b, _ := json.Marshal(p)
	fmt.Println(string(b)) //{"Name":"a","Gender":"male","Age":23}
}
  • 只支持struct中导出的field才能被序列化,即首字母大写的field
  • GO中不是所有类型都支持序列化,其中key只支持string
  • 无法对channel,complex,function序列化
  • 数据中如存在循环引用,不支持序列化,因为会递归。
  • pointer序列化后是其指向的值或者是nil
Struct Tag
指定 JSON filed name

序列化后的json串中的name一般为小写,我们通过struct tag实现

指定field为empty

使用omitempty告诉Marshal函数,如field对应类型为zero-value,那么序列化的json对象中不包含此field

跳过field

仅使用"-"表示跳过指定的field,保护某些字段不被序列化

type Person struct {
	Name   string `json:"name"`
	Gender string `json:"gender"`
	Age    uint32 `json:"age,omitempty"`
	Passwd string `json:"-"`
}

	// 默认初始化
	p := Person{"a", "male", 23, "mimi"}
	fmt.Println(p)
	fmt.Printf("%v\n", p) //{a male 23}

	// 指定成员初始化
	p1 := Person{Name: "wsq", Gender: "male"}
	fmt.Println(p1) //{wsq male 0}

	// 序列化
	b, _ := json.Marshal(p)
	fmt.Println(string(b)) //{"Name":"a","Gender":"male","Age":23}

	// 反序列化
	var pp Person
	err := json.Unmarshal(b, &pp)
	if err != nil {
		errors.New("unmarshal error")
	}
	fmt.Printf("%T, %v\n", pp, pp)

	// Struct Tag
	// 指定JSON的field name
	c, _ := json.Marshal(p)
	fmt.Println(string(c)) //{"name":"a","gender":"male","age":23}

	// 指定field是empty时的行为
	d, _ := json.Marshal(p1)
	fmt.Println(string(d)) //{"name":"wsq","gender":"male"}
	// 跳过指定field
	importPerson := Person{Name: "wsq", Passwd: "password"}
	importPersonMar, _ := json.Marshal(importPerson)
	fmt.Println(string(importPersonMar)) //{"name":"wsq","gender":""}
二、反序列化

发序列化函数 Unmarshal ,函数签名:

func Unmarshal(data []byte, v interface{}) error

此时,我们需要创建一个可序列化的byte切片,将其转换为struct。
默认的json支持:bool, float64, string,nil几种Go类型

反序列化处理未知JSON数据格式

使用interface{}存储
举例:

    b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
	var f interface{}
	err := json.Unmarshal(b, &f)
	if err != nil {
		errors.New("unmarshal error")
	}
	fmt.Printf("%T, %v\n", f, f)

输出:

类型: map[string]interface {}
内容: map[Age:6 Name:Wednesday Parents:[Gomez Morticia]]

可以发现,此时keystring类型,value是存储在interface {}中的,我们可以通过type assertion获取:

	m := f.(map[string]interface{})
	for k, v := range m {
		switch vv := v.(type) {
		case string:
			fmt.Println(k, "is string", vv)
		case float64:
			fmt.Println(k, "is float64", vv)
		case []interface{}:
			fmt.Println(k, "is an array:")
			for i, u := range vv {
				fmt.Println(i, u)
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
反序列化处理slice、map、pointer

举例:

type FamilyMember struct {
	Name    string
	Age     int
	Parents []string
}

func main() {
	b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
	var n FamilyMember
	json.Unmarshal(b, &n)
	fmt.Printf("%T, %v\n", n, n)

}

struct中存在一个slice类型,默认值为nil。

  • 序列化时,若不为nil,则解引用获得其指向的值,然后序列化
  • 反序列化时首先对其初始化为nil,之后再赋值
三、其他序列化函数

函数:

// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
    return &Encoder{w: w, escapeHTML: true}
}

// NewDecoder returns a new decoder that reads from r.
func NewDecoder(r io.Reader) *Decoder {
    return &Decoder{r: r}
}

func (enc *Encoder) Encode(v interface{}) error {
    // ...
}

举例:
除了 marshal 和 unmarshal 函数,Go 还提供了 Decoder 和 Encoder 对 stream JSON 进行处理。

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	var err error
	person1 := Person{"张三", 30}
	// 编码结果暂存到 buffer
	bytes1 := new(bytes.Buffer)
	_ = json.NewEncoder(bytes1).Encode(person1)
	if err == nil {
		fmt.Print(" 编码结果: ", string(bytes1.Bytes()))
	}

	// 解码
	str2 := bytes1.String()
	var person2 Person
	// 创建一个 string reader 作为参数
	err = json.NewDecoder(strings.NewReader(str2)).Decode(&person2)
	if err == nil {
		fmt.Println(" 解码结果: ", person2.Name, person2.Age)
	}

}
四、nest struct序列化
type App struct {
	Id string `json:"id"`
}

type Org struct {
	Name string `json:"name"`
}

type AppWithOrg struct {
	App
	Org
}

func main() {
	data := []byte(`
        {
            "id": "k34rAT4",
            "name": "My Awesome Org"
        }
    `)

	var b AppWithOrg

	json.Unmarshal(data, &b)
	fmt.Printf("%#v", b)

	a := AppWithOrg{
		App: App{
			Id: "k34rAT4",
		},
		Org: Org{
			Name: "My Awesome Org",
		},
	}
	data, _ = json.Marshal(a)
	fmt.Println(string(data))
}

vscode 工具相关
1. 删除当前行ctrl + shift +k
2. vscode插件 String Manipulation 字符串转换处理(驼峰、大写开头、下划线等等)
   使用时ctrl+shift+p 输入camel即可
3. ctrl+f5直接编译简单go文件

参考:/?id=10
/post/5d5cbc20f265da03ab425227