1.Json.Marshal会有什么问题?
下边示例是将json序列化成bytes,然后把bytes反序列化到匹配的结构体。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
func main() {
in := `{"firstName":"John","lastName":"Dow"}`
bytes, err := json.Marshal(in)
if err != nil {
panic(err)
}
var p Person
err = json.Unmarshal(bytes, &p)
if err != nil {
panic(err)
}
fmt.Printf("%+v", p)
}
运行程序发现,程序panic了。
panic: json: cannot unmarshal string into Go value of type main.Person
goroutine 1 [running]:
main.main()
/tmp/sandbox071126523/prog.go:24 +0x1e9
这不是我们想要的,接下来我们确认下json字符串是否跟Person
结构体相匹配。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
func main() {
bytes, err := json.Marshal(Person{
FirstName: "John",
LastName: "Dow",
})
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
}
输出的结果如下:
{"firstName":"John","lastName":"Dow"}
序列化后的结构体,跟我们的json字符串是一样的。
2.原因是什么?
我们比较一下序列化json字符串以及结构体序列化的结果。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
func main() {
bytes, err := json.Marshal(Person{
FirstName: "John",
LastName: "Dow",
})
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
in := `{"firstName":"John","lastName":"Dow"}`
bytes, err = json.Marshal(in)
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
}
输出结果如下:
{"firstName":"John","lastName":"Dow"}
"{\"firstName\":\"John\",\"lastName\":\"Dow\"}"
你能看到转义的双引号么?这是问题的症结所在,json.Marshal在对字符串进行序列化的时候,会对字符串进行转义。
3.如何避免被转义
json包对这个问题有一个解决方案,它有一个RawMessage
类型,在序列化及反序列化时不会对字符串进行转义。
所以,如果你需要序列化一个json字符串,后续再反序列化到结构体里,可以用json.RawMessage
来实现。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
func main() {
in := `{"firstName":"John","lastName":"Dow"}`
rawIn := json.RawMessage(in)
bytes, err := rawIn.MarshalJSON()
if err != nil {
panic(err)
}
var p Person
err = json.Unmarshal(bytes, &p)
if err != nil {
panic(err)
}
fmt.Printf("%+v", p)
}
输出结果如下:
{FirstName:John LastName:Dow}
是正确的结果。
4.有没有更简单的方式
有的,json.RawMessage
实际上是[]byte
类型的,所以你需要做的就是把字符串转换成[]byte
类型。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
func main() {
in := `{"firstName":"John","lastName":"Dow"}`
bytes := []byte(in)
var p Person
err := json.Unmarshal(bytes, &p)
if err != nil {
panic(err)
}
fmt.Printf("%+v", p)
}
输出结果是一样的:
{FirstName:John LastName:Dow}