json.Marshal
进行序列化json.Marshal
函数可以将 Go 的数据结构转换为 JSON 格式的字节切片([]byte
)
package main
import (
"encoding/json"
"fmt"
"log"
)
// 定义一个结构体
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Height float64 `json:"height,omitempty"` // omitempty 表示如果字段为空则忽略
Address string `json:"-"` //序列化时忽略该字段
}
func main() {
// 创建一个 Person 实例
person := Person{
Name: "张三",
Age: 30,
// Height 未设置,序列化时将被忽略
Address: "北京", // 由于标签 `json:"-"`序列化时忽略该字段
}
// 序列化为 JSON
jsonData, err := json.Marshal(person)
if err != nil {
log.Fatalf("JSON 序列化失败: %v", err)
}
// 输出 JSON 字符串
fmt.Println(string(jsonData))
}
{"name":"张三","age":30}
解释:
Name
和 Age
字段被成功序列化为 JSON。Height
字段由于未设置值,并且有 omitempty
标签,因此在 JSON 中被忽略。Address
字段由于标签 json:"-"
-----json.Unmarshal
进行反序列化json.Unmarshal
函数可以将 JSON 数据解析并填充到 Go 的数据结构中。其函数签名如下:
func Unmarshal(data []byte, v interface{}) error
data
:要反序列化的 JSON 数据,类型为 []byte
。v
:指向要填充数据的 Go 数据结构的指针。nil
;否则,返回相应的错误信息。package main
import (
"encoding/json"
"fmt"
"log"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Height float64 `json:"height,omitempty"`
Address string `json:"-"`
}
func main() {
// JSON 数据
jsonData := `{
"name": "张三",
"age": 30,
"height": 175.5
}`
// 创建一个 Person 实例
var person Person
// 反序列化 JSON 数据到 person 结构体
err := json.Unmarshal([]byte(jsonData), &person)
if err != nil {
log.Fatalf("JSON 反序列化失败: %v", err)
}
// 输出结果
fmt.Printf("姓名: %s, 年龄: %d, 身高: %.1f\n", person.Name, person.Age, person.Height)
}
姓名: 张三, 年龄: 30, 身高: 175.5
解释:
Name
和 Age
字段成功从 JSON 中提取并赋值给结构体字段。Height
字段根据 JSON 数据被赋值为 175.5
。Address
字段由于标签 json:"-"
结构体标签可以控制字段JSON 中的名称、是否忽略等。例如:
type Person struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Age int `json:"-"`
}
json:"first_name"
:将字段序列化为 first_name
。json:"-"
Go 的布尔值和数字类型会自动转换为 JSON 中的 true
/false
和数值。
type Status struct {
Active bool `json:"active"`
Score float64 `json:"score"`
}
status := Status{
Active: true,
Score: 95.5,
}
jsonData, _ := json.Marshal(status)
fmt.Println(string(jsonData)) // {"active":true,"score":95.5}
Go 的数组和切片会被序列化为 JSON 数组。
type Scores struct {
Name string `json:"name"`
Scores []float64 `json:"scores"`
}
scores := Scores{
Name: "李四",
Scores: []float64{85.0, 90.5, 78.0},
}
jsonData, _ := json.Marshal(scores)
fmt.Println(string(jsonData)) // {"name":"李四","scores":[85,90.5,78]}
可以在 Go 结构体中嵌套其他结构体,JSON 也会相应嵌套。
type Address struct {
City string `json:"city"`
State string `json:"state"`
}
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
}
person := Person{
Name: "王五",
Age: 25,
Address: Address{
City: "上海",
State: "上海",
},
}
jsonData, _ := json.Marshal(person)
fmt.Println(string(jsonData))
// {"name":"王五","age":25,"address":{"city":"上海","state":"上海"}}
有时候默认的序列化行为不能满足需求,可以通过实现 json.Marshaler
接口来自定义序列化逻辑。
json.Marshaler
接口type CustomDate struct {
Year int
Month int
Day int
}
func (c CustomDate) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%d-%02d-%02d\"", c.Year, c.Month, c.Day)), nil
}
type Event struct {
Name string `json:"name"`
Date CustomDate `json:"date"`
}
event := Event{
Name: "会议",
Date: CustomDate{Year: 2023, Month: 10, Day: 1},
}
jsonData, _ := json.Marshal(event)
fmt.Println(string(jsonData)) // {"name":"会议","date":"2023-10-01"}
使用指针可以让字段在序列化时有条件地包含或不包含。
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email *string `json:"email,omitempty"` // 如果 Email 为 nil,则字段被忽略
}
user := User{
Name: "赵六",
Age: 28,
// Email 未设置,序列化时将被忽略
}
jsonData, _ := json.Marshal(user)
fmt.Println(string(jsonData)) // {"name":"赵六","age":28}
// 设置 Email
email := "[email protected]"
user.Email = &email
jsonData, _ = json.Marshal(user)
fmt.Println(string(jsonData)) // {"name":"赵六","age":28,"email":"[email protected]"}
在实际使用中,应该总是检查 json.Marshal
返回的错误,以确保序列化过程没有问题。
jsonData, err := json.Marshal(person)
if err != nil {
log.Fatalf("JSON 序列化失败: %v", err)
}
常见的错误包括:
encoding/json
不支持循环结构体的序列化)。以下是一个综合示例,展示了多种序列化场景:
package main
import (
"encoding/json"
"fmt"
"log"
)
type Address struct {
City string `json:"city"`
State string `json:"state"`
}
type Person struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Age int `json:"age,omitempty"`
Height float64 `json:"height,omitempty"`
Address Address `json:"address,omitempty"`
Tags []string `json:"tags,omitempty"`
Birthday *CustomDate `json:"birthday,omitempty"`
}
type CustomDate struct {
Year int
Month int
Day int
}
func (c CustomDate) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%d-%02d-%02d\"", c.Year, c.Month, c.Day)), nil
}
func main() {
person := Person{
FirstName: "孙",
LastName: "七",
Age: 32,
Address: Address{
City: "广州",
State: "广东",
},
Tags: []string{"developer", "gopher"},
Birthday: &CustomDate{
Year: 1991,
Month: 5,
Day: 20,
},
}
jsonData, err := json.MarshalIndent(person, "", " ")
if err != nil {
log.Fatalf("JSON 序列化失败: %v", err)
}
fmt.Println(string(jsonData))
}
{
"first_name": "孙",
"last_name": "七",
"age": 32,
"address": {
"city": "广州",
"state": "广东"
},
"tags": [
"developer",
"gopher"
],
"birthday": "1991-05-20"
}
说明:
json.MarshalIndent
可以生成格式化的 JSON,便于阅读。map[string]interface{}
处理动态 JSON有时候,JSON 的结构在编译时未知,可以使用 map[string]interface{}
来处理动态 JSON 数据。
func main() {
jsonData := `{
"name": "孙七",
"age": 32,
"hobbies": ["reading", "gaming", "coding"],
"address": {
"city": "广州",
"state": "广东"
}
}`
var result map[string]interface{}
err := json.Unmarshal([]byte(jsonData), &result)
if err != nil {
log.Fatalf("JSON 反序列化失败: %v", err)
}
fmt.Println("姓名:", result["name"])
fmt.Println("年龄:", result["age"])
// 处理切片
hobbies, ok := result["hobbies"].([]interface{})
if ok {
fmt.Print("爱好: ")
for _, hobby := range hobbies {
fmt.Printf("%v ", hobby)
}
fmt.Println()
}
// 处理嵌套的 map
address, ok := result["address"].(map[string]interface{})
if ok {
fmt.Printf("城市: %v, 州: %v\n", address["city"], address["state"])
}
}
姓名: 孙七
年龄: 32
爱好: reading gaming coding
城市: 广州, 州: 广东
注意: 使用 map[string]interface{}
时,所有的值都是 interface{}
类型,需要通过类型断言将其转换为具体的类型。
有时候,默认的反序列化行为不能满足需求,可以通过实现 json.Unmarshaler
接口来自定义反序列化逻辑。
json.Unmarshaler
接口type CustomDate struct {
Year int
Month int
Day int
}
func (c *CustomDate) UnmarshalJSON(data []byte) error {
// 假设 JSON 中的日期格式为 "YYYY-MM-DD"
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
// 解析字符串日期
_, err := fmt.Sscanf(s, "%d-%d-%d", &c.Year, &c.Month, &c.Day)
return err
}
type Event struct {
Name string `json:"name"`
Date CustomDate `json:"date"`
}
func main() {
jsonData := `{"name":"会议","date":"2023-10-01"}`
var event Event
err := json.Unmarshal([]byte(jsonData), &event)
if err != nil {
log.Fatalf("JSON 反序列化失败: %v", err)
}
fmt.Printf("事件: %s, 日期: %d-%02d-%02d\n", event.Name, event.Date.Year, event.Date.Month, event.Date.Day)
}
事件: 会议, 日期: 2023-10-01
在实际使用中,应该总是检查 json.Unmarshal
返回的错误,以确保反序列化过程没有问题。
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
jsonData := `{"name":"赵六","age":"二十八"}` // age 应为数字
var user User
err := json.Unmarshal([]byte(jsonData), &user)
if err != nil {
log.Fatalf("JSON 反序列化失败: %v", err)
}
上述代码会因为 age
字段类型不匹配而导致反序列化失败,并输出相应的错误信息。
package main
import (
"encoding/json"
"fmt"
"log"
)
type Address struct {
City string `json:"city"`
State string `json:"state"`
}
type Person struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Age int `json:"age,omitempty"`
Height float64 `json:"height,omitempty"`
Address Address `json:"address,omitempty"`
Tags []string `json:"tags,omitempty"`
Birthday *CustomDate `json:"birthday,omitempty"`
}
type CustomDate struct {
Year int
Month int
Day int
}
func (c *CustomDate) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
_, err := fmt.Sscanf(s, "%d-%d-%d", &c.Year, &c.Month, &c.Day)
return err
}
func main() {
jsonData := `{
"first_name": "孙",
"last_name": "七",
"age": 32,
"height": 175.5,
"address": {"city":"广州","state":"广东"},
"tags": ["developer", "gopher"],
"birthday": "1991-05-20"
}`
var person Person
err := json.Unmarshal([]byte(jsonData), &person)
if err != nil {
log.Fatalf("JSON 反序列化失败: %v", err)
}
fmt.Printf("姓名: %s %s, 年龄: %d, 身高: %.1f\n", person.FirstName, person.LastName, person.Age, person.Height)
fmt.Printf("地址: %s, %s\n", person.Address.City, person.Address.State)
fmt.Printf("标签: %v\n", person.Tags)
if person.Birthday != nil {
fmt.Printf("生日: %d-%02d-%02d\n", person.Birthday.Year, person.Birthday.Month, person.Birthday.Day)
}
}
姓名: 孙 七, 年龄: 32, 身高: 175.5
地址: 广州, 广东
标签: [developer gopher]
生日: 1991-05-20