
在go语言中,当尝试将一个包含数据的结构体通过encoding/json包的json.marshal函数序列化为json字符串时,有时会得到一个空的json对象{},但同时json.marshal返回的错误err却是nil。这常常让初学者感到困惑,因为结构体本身明明包含了数据,且没有报告任何错误。
考虑以下示例代码,它定义了Address、Name和Person三个结构体,并尝试将一个Person实例序列化为JSON:
package main
import (
"encoding/json"
"fmt"
)
type Address struct {
street string
extended string
city string
state string
zip string
}
type Name struct {
first string
middle string
last string
}
type Person struct {
name Name
age int
address Address
phone string
}
func main() {
myname := Name{"Alfred", "H", "Eigenface"}
myaddr := Address{"42 Place Rd", "Unit 2i", "Placeton", "ST", "00921"}
me := Person{myname, 24, myaddr, "000 555-0001"}
b, err := json.Marshal(me)
if err != nil {
fmt.Println("Error marshalling:", err)
return
}
fmt.Println("Marshalled JSON:", string(b)) // 输出: Marshalled JSON: {}
fmt.Println("Original Person struct:", me) // 输出: Original Person struct: { {Alfred H Eigenface} 24 {42 Place Rd Unit 2i Placeton ST 00921} 000 555-0001}
}
从上述输出可以看出,string(b)打印的是一个空的JSON对象{},而me结构体实例本身的数据是完整的。
造成json.Marshal返回空对象的核心原因在于Go语言的字段导出(Exported Fields)规则。在Go语言中,一个结构体的字段是否能被包外访问(或被其他包的函数处理),取决于其名称的首字母大小写。
encoding/json包在进行JSON序列化时,只会处理结构体中已导出的(首字母大写)字段。对于未导出的字段,json.Marshal会直接忽略它们,不会将其包含在生成的JSON输出中。
立即学习“go语言免费学习笔记(深入)”;
在本例中,Address、Name和Person结构体中的所有字段(如street, first, age等)都是首字母小写的,因此它们都是未导出的私有字段。json.Marshal在尝试序列化这些结构体时,发现没有可导出的字段,所以最终生成了一个空的JSON对象。
为什么err是nil?err为nil表示json.Marshal函数在执行过程中没有遇到任何编码或语法错误。它仅仅表明所有“可访问”(即已导出)的字段都被正确地处理了。由于本例中没有可导出的字段,所以没有错误发生,但结果自然也是空的。
要解决这个问题,只需将需要序列化到JSON中的结构体字段的首字母改为大写,使其成为已导出的字段。
修改后的结构体定义如下:
package main
import (
"encoding/json"
"fmt"
)
// Address 结构体,字段首字母大写以导出
type Address struct {
Street string
Extended string
City string
State string
Zip string
}
// Name 结构体,字段首字母大写以导出
type Name struct {
First string
Middle string
Last string
}
// Person 结构体,字段首字母大写以导出
type Person struct {
Name Name
Age int
Address Address
Phone string
}
func main() {
myname := Name{"Alfred", "H", "Eigenface"}
myaddr := Address{"42 Place Rd", "Unit 2i", "Placeton", "ST", "00921"}
me := Person{myname, 24, myaddr, "000 555-0001"}
b, err := json.Marshal(me)
if err != nil {
fmt.Println("Error marshalling:", err)
return
}
fmt.Println("Marshalled JSON:", string(b))
fmt.Println("Original Person struct:", me)
}运行上述修改后的代码,将得到以下JSON输出:
Marshalled JSON: {"Name":{"First":"Alfred","Middle":"H","Last":"Eigenface"},"Age":24,"Address":{"Street":"42 Place Rd","Extended":"Unit 2i","City":"Placeton","State":"ST","Zip":"00921"},"Phone":"000 555-0001"}
Original Person struct: {{Alfred H Eigenface} 24 {42 Place Rd Unit 2i Placeton ST 00921} 000 555-0001}此时,json.Marshal成功地将结构体数据序列化为完整的JSON字符串。
虽然将字段首字母大写可以解决序列化问题,但在某些情况下,我们可能希望JSON输出的字段名与Go结构体中的字段名不同,或者希望忽略某些已导出的字段。这时,可以使用结构体标签(json tag)来实现更灵活的控制。
例如,如果我们希望Street字段在JSON中显示为street_address,并且忽略Phone字段:
package main
import (
"encoding/json"
"fmt"
)
type Address struct {
Street string `json:"street_address"` // JSON输出为 street_address
Extended string `json:"extended_info,omitempty"` // 如果为空,则不输出
City string `json:"city"`
State string `json:"state"`
Zip string `json:"zip"`
}
type Name struct {
First string `json:"first_name"`
Middle string `json:"middle_name,omitempty"`
Last string `json:"last_name"`
}
type Person struct {
Name Name `json:"full_name"`
Age int `json:"age"`
Address Address `json:"address_details"`
Phone string `json:"-"` // 使用 "-" 标签表示该字段在JSON中被忽略
}
func main() {
myname := Name{"Alfred", "H", "Eigenface"}
myaddr := Address{"42 Place Rd", "", "Placeton", "ST", "00921"} // extended 为空
me := Person{myname, 24, myaddr, "000 555-0001"}
b, err := json.Marshal(me)
if err != nil {
fmt.Println("Error marshalling:", err)
return
}
fmt.Println("Marshalled JSON with tags:", string(b))
}输出结果将是:
Marshalled JSON with tags: {"full_name":{"first_name":"Alfred","last_name":"Eigenface"},"age":24,"address_details":{"street_address":"42 Place Rd","city":"Placeton","state":"ST","zip":"00921"}}可以看到,Street被改名为street_address,Extended字段因为值为空且有omitempty标签而被省略,Phone字段也被完全忽略。
通过理解Go语言的字段导出规则,并正确地应用它,开发者可以有效避免json.Marshal返回空JSON对象的问题,确保数据能够按照预期被序列化和反序列化。
以上就是Go语言中结构体JSON序列化为空的深度解析与解决方案的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号