耐心和持久胜过激烈和狂热。
哈喽大家好,我是陈明勇,本文分享的内容是 Go 结构体与 JSON 之间的转换。如果本文对你有帮助,不妨点个赞,如果你是 Go 语言初学者,不妨点个关注,一起成长一起进步,如果本文有错误的地方,欢迎指出!
前言
在日常开发中,我们往往会将 JSON
解析成对应的结构体,反之也会将结构体转成 JSON
。接下来本文会通过 JSON
包的两个函数,来介绍 JSON
与结构体之间的转换。
结构体转 JSON
Marshal(v any) ([]byte, error)
:将 v
转成 JSON
数据,以 []byte
的形式返回。
import ( "encoding/json" "fmt" ) type User struct { Name string Age int Height float64 Weight *float64 Child bool marriageStatus string } func main() { weight := 120.5 user := User{ Name: "gopher", Age: 18, Height: 180.5, Weight: &weight, Child: false, marriageStatus: "未婚", } jsonBytes, err := json.Marshal(user) if err != nil { fmt.Println("error: ", err) return } fmt.Println(string(jsonBytes)) // {"Name":"gopher","Age":18,"Height":180.5,"Weight":120.5,"Child":false} } 复制代码
执行结果:{"Name":"gopher","Age":18,"Height":180.5,"Weight":120.5,"Child":false}
根据结果可知:
- 不可导出字段(字段名以小写字母开头),是不能被转成
JSON
的key
的,这也符合Go
的语法规定,以小写字母开头的变量或结构体字段等,不能在包外被访问。 - 转换后的字段名,与结构体字段的名字一样。
- 如果字段是指针类型,转换后的值为指针指向的字段值。
如果我们想要指定字段转换之后的命名,或者将一个可导出的字段进行忽略,可以通过给结构体字段打上 JSON
标签的方式实现。
import ( "encoding/json" "fmt" ) type User struct { Name string `json:"name"` Age int `json:"age"` Height float64 `json:"height"` Weight *float64 `json:"weight"` Child bool `json:"child"` MarriageStatus string `json:"-"` } func main() { weight := 120.5 user := User{ Name: "gopher", Age: 18, Height: 180.5, Weight: &weight, Child: false, MarriageStatus: "未婚", } jsonBytes, err := json.Marshal(user) if err != nil { fmt.Println("error: ", err) return } fmt.Println(string(jsonBytes)) // {"name":"gopher","age":18,"height":180.5,"weight":120.5,"child":false} } 复制代码
通过给结构体字段定打上 JSON
标签,可指定转成 JSON
后的字段名,如果 JSON
标签的值为 -
,则在转换 JSON
时忽略此字段。
JSON 解析结构体
Unmarshal(data []byte, v any) error
:将 JSON
解析成指定的结构体。
import ( "encoding/json" "fmt" ) type User struct { Name string `json:"name"` Age int `json:"age"` Height float64 `json:"height"` Child bool `json:"-"` marriageStatus string } func main() { userStr := ` { "name": "gopher", "age": 18, "height": 180.5, "child": true, "marriageStatus": "未婚" } ` user := &User{} err := json.Unmarshal([]byte(userStr), &user) if err != nil { fmt.Println("error: ", err) return } fmt.Printf("%#v", user) // &main.User{Name:"gopher", Age:18, Height:180.5, Child:false, marriageStatus:""} } 复制代码
执行结果:&main.User{Name:"gopher", Age:18, Height:180.5, Child:false, marriageStatus:""}
根据结果可知:
- 使用
Unmarshal
函数时,我们需要传入结构体的指针类型,否则结构体字段的值将不会被改变,因为底层是通过指针去修改结构体字段的值。 JSON
解析时,JSON
的key
与结构体字段的匹配规则是:
- 优先查找
JSON
标签值和key
一样的,找到则将value
赋值给对应字段。 - 如果没有
JSON
标签值与key
相匹配,则根据字段名进行匹配。
- 可以发现,如果结构体字段是非导出字段或
JSON
标签的值为-
,将不会被匹配到。
小结
本文介绍了 Go
语言里,JSON
与结构体之间的转换。在结构体转 JSON
时,我们可以通过给字段打标签,指定转换后的 key
命名,需要注意的是,如果结构体的字段为非导出字段或字段的 JSON
标签值为 -
,在转换 JSON
时,将会被忽略。反之 JSON
解析结构体时也是一样的。