跳过正文
  1. 文章/
  2. GoLang/
  3. 常用包/
  4. 标准包/

4、encoding

·1225 字·3 分钟· loading · loading · ·
GoLang 常用包 标准包
GradyYoung
作者
GradyYoung
标准包 - 点击查看当前系列文章
§ 4、encoding 「 当前文章 」

golang中内置encoding包的各个子包,提供了各种数据与编码、文本格式之间转换的方法

JSON
#

JSON支持以下数据类型:

  • 数字:整数或浮点数,如 1233.14
  • 字符串:用双引号包围的文本,如 "Hello, World"
  • 布尔值truefalse
  • 数组:有序的值集合,用方括号表示,如 [1, 2, 3]
  • 对象:键值对集合,用花括号表示,如 {"name": "John", "age": 30}
  • null:表示空值,如 {"address": null}

Go的encoding/json包会根据以下规则在JSON和Go类型之间进行映射:

JSON类型 Go类型
对象 struct, map[string]T
数组 slice, array
字符串 string
数字 int, int8, …, int64, uint, uint8, …, uint64, float32, float64
布尔值 bool
null nil

结构体标签
#

type User struct {
	Name     string `json:"user_name"`       // 序列化为 {"user_name": "Alice"}
	Age      int    `json:"age,omitempty"`   // 零值时忽略(如 0)
	Email    string `json:"email,omitempty"` // 零值时忽略(如 "")
	Password string `json:"-"`               // 完全忽略该字段
}

Marshal、Unmarshal
#

  • Struct tag 可以决定 Marshal 和 Unmarshal 函数,如果没有声明Tag,就会使用字段名
  • 只有 struct 中支持导出的 field 才能被 JSON package 序列化,即首字母大写的 field
  • JSON object key 只支持 string
  • Channel、complex、function 等 type 无法进行序列化
  • 数据中如果存在循环引用,则不能进行序列化,因为序列化时会进行递归
  • Pointer 序列化之后是其指向的值或者是 nil
//将对象v序列化为json格式,并返回byte切片
func Marshal(v any) ([]byte, error)
//将对象v序列化为json格式,并返回byte切片,prefix为前缀,indent为缩进
func MarshalIndent(v any, prefix, indent string) ([]byte, error)
//将json字符串的byte切片反序列化到对象v中
func Unmarshal(data [] byte, v any) error
package main

import (
	"encoding/json"
	"fmt"
)

type Stu struct {
	Id   string `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	s1 := Stu{"s1", "lucy", 18}
	s2 := Stu{"s2", "tom", 20}
	data := []Stu{s1, s2}
	b, err := json.Marshal(data)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(b)) 
    //[{"id":"s1","name":"lucy","age":18},{"id":"s2","name":"tom","age":20}]
}
package main

import (
	"encoding/json"
	"fmt"
)

type Stu struct {
	Id   string `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	j := `[{"id":"s1","name":"lucy","age":18},{"id":"s2","name":"tom","age":20}]`
	var data []Stu
	err := json.Unmarshal([]byte(j), &data)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(data) //[{s1 lucy 18} {s2 tom 20}]
}

Encode、Decode
#

除了 marshal 和 unmarshal 函数,Go 还提供了 Decoder 和 Encoder 对 stream JSON 进行处理,常见 request 中的 Body、文件等。

package main

import (
	"encoding/json"
	"fmt"
	"os"
)

type Stu struct {
	Id   string `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	s1 := Stu{"s1", "lucy", 18}
	s2 := Stu{"s2", "tom", 20}
	data := []Stu{s1, s2}
	f, err := os.OpenFile("./stu.json", os.O_WRONLY|os.O_CREATE, 0777)
	if err != nil {
		fmt.Println(err)
	}
	defer f.Close()
	encoder := json.NewEncoder(f)
	err = encoder.Encode(data)
	if err != nil {
		fmt.Println(err)
	}
}
package main

import (
	"encoding/json"
	"fmt"
	"os"
)

type Stu struct {
	Id   string `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	var data []Stu
	f, err := os.Open("./stu.json")
	if err != nil {
		fmt.Println(err)
	}
	defer f.Close()
	decoder := json.NewDecoder(f)
	err = decoder.Decode(&data)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(data) //[{s1 lucy 18} {s2 tom 20}]
}

自定义序列化规则
#

在encoding/json包中有两个非常重要的接口,如果任意自定义类型实现了Marshaler或者Unmarshaler接口,就能实现自定义的序列化或者反序列化规则

type Marshaler interface {
 MarshalJSON() ([]byte, error)
}

type Unmarshaler interface {
 UnmarshalJSON([]byte) error
}

例如,现在我们有一个结构体,其中的 Time 类型字段按照默认的序列化规则是这样的

package main

import (
	"encoding/json"
	"fmt"
	"time"
)

type User struct {
	Name     string
	Birthday time.Time
}

func main() {
	u := User{Name: "Tom", Birthday: time.Now()}
	marshal, err := json.Marshal(&u)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(marshal)) // {"Name":"Tom","Birthday":"2024-06-26T09:11:28.585563+08:00"}
}

现在我们只需要自己声明一个类型Time并且实现MarshalerUnmarshaler接口即可自定义该字段的序列化规则

package main

import (
	"encoding/json"
	"fmt"
	"time"
)

type Time time.Time

var timeFormat = "2006-01-02 15:04:05"

func (t *Time) MarshalJSON() ([]byte, error) {
	format := time.Time(*t).Format(timeFormat)
	return []byte(`"` + format + `"`), nil
}

func (t *Time) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	location, err := time.ParseInLocation(timeFormat, s, time.Local)
	if err != nil {
		return err
	}
	*t = Time(location)
	return nil
}

type User struct {
	Name     string
	Birthday Time
}

func main() {
	u := User{Name: "Tom", Birthday: Time(time.Now())}
	marshal, err := json.Marshal(&u)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(marshal)) // {"Name":"Tom","Birthday":"2024-06-26 09:25:17"}
}
标准包 - 点击查看当前系列文章
§ 4、encoding 「 当前文章 」