golang中内置encoding包的各个子包,提供了各种数据与编码、文本格式之间转换的方法
JSON #
JSON支持以下数据类型:
- 数字:整数或浮点数,如
123或3.14 - 字符串:用双引号包围的文本,如
"Hello, World" - 布尔值:
true或false - 数组:有序的值集合,用方括号表示,如
[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并且实现Marshaler和Unmarshaler接口即可自定义该字段的序列化规则
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"}
}