对于结构体大家都很熟悉,是一种自定义类型,可以将不同类型的同属于这个类的属性(成员变量)集合在一起,换句话说这些成员变量属于键值对,那么这种也就是常见的json格式,我们来看下如何将结构体转成json格式的字符串。
Marshal转字符串
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Tall float32
Hobby string
}
func main() {
//实例化的时候要注意,最后的逗号不能省略
p := Person{
Name: "Tony", Tall: 173.5, Hobby: "Reading",
}
fmt.Println(p) //{Tony 173.5 Reading}
json_p, err := json.Marshal(p)
fmt.Printf("%T,%s,%v", string(json_p), string(json_p), err)
//string,{"Name":"Tony","Tall":173.5,"Hobby":"Reading"},<nil>
}
如果结构体成员变量名称的首字母是小写的话,会发生什么情况?
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Tall float32
Hobby string
address string //首字母小写
Sex string
}
func main() {
//实例化的时候要注意,最后的逗号不能省略
p := Person{
Name: "Tony", Tall: 173.5, Hobby: "Reading", address: "湖南省", Sex: "男",
}
fmt.Println(p) //{Tony 173.5 Reading 湖南省 男}
json_p, err := json.Marshal(p)
fmt.Printf("%T,%s,%v", string(json_p), string(json_p), err)
//string,{"Name":"Tony","Tall":173.5,"Hobby":"Reading","Sex":"男"},<nil>
}
我们发现这个address成员变量没有转换成功,没有出现,那说明如果需要转成json,首字母必须大写。然后我们反过来将json字符串转换成结构体,看下有什么变化。
var out Person
json.Unmarshal(json_p, &out)
fmt.Printf("%T,%#v,%v", out, out, err)
//main.Person,main.Person{Name:"Tony", Tall:173.5, Hobby:"Reading", address:"", Sex:"男"},<nil>
address的内容是空,如果是整型,内容是0,这验证了,如果外部需获取成员变量的情况,首字母需大写。
结构体嵌套
结构体是多个类型的集合,所以除了基本类型之外,自定义类型肯定也是可以一起放在里面,无差别对待使用,而结构体里面的结构体可以是指针也可以不是指针,不过建议使用指针的表示形式,这个只是一个内存地址而已,效率要快。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Tall float32
Hobby string
address string //首字母小写
Sex string
Game *Game //指向一个玩过什么游戏的一个结构体,也可以不使用指针,指针要快
}
type Game struct {
Name1 string
Name2 string
}
func main() {
//实例化的时候要注意,最后的逗号不能省略
p := Person{
Name: "Tony", Tall: 173.5, Hobby: "Reading", address: "湖南省", Sex: "男",
}
//指针用法
game := new(Game)
game.Name1 = "星际争霸"
game.Name2 = "王者荣耀"
p.Game = game
/*
非指针用法
game := Game{Name1: "王者荣耀", Name2: "魔兽世界"}
p.Game = game
*/
json_p, err := json.Marshal(p)
if err != nil {
fmt.Println("转换json字符串失败!")
}
fmt.Printf("%T,%s", string(json_p), string(json_p))
}
//string,{"Name":"Tony","Tall":173.5,"Hobby":"Reading","Sex":"男","Game":{"Name1":"星际争霸","Name2":"王者荣耀"}}
结构体接口
看过Go语言进阶,interface接口,socket套接字这篇文章的伙伴就应该知道,其中的 tester = p 就是将类型赋值给了接口。我们现在来改造这个结构体,使其变得更加的通用,也就是说不管什么类型都可以,而不是指定了string就只能是字符串类型。
type Person struct {
Name interface{}
Tall interface{}
Hobby interface{}
address interface{} //首字母小写
Sex interface{}
Game interface{}
}
然后我们将那个Hobby爱好,原来是字符串的,我们使用整型为其赋值,试下:
p := Person{
Name: "Tony", Tall: 173.5, Hobby: 123, address: "湖南省", Sex: "男",
}
//string,{"Name":"Tony","Tall":173.5,"Hobby":123,"Sex":"男","Game":{"Name1":"星际争霸","Name2":"王者荣耀"}}
OK,没有问题!
所有类型全部替换成interface{}空接口,因为在go语言中的每一种类型都实现了该接口,换句话说就是任何其他类型的数据都可以赋值给interface{}类型
Unmarshal字符串转结构体
json字符串转化成结构体的话,关键是json的字符串格式要严格符合规范,如:双引号需要反斜杠进行转义操作,括号要匹配不能缺失等。Unmarshal两个参数,一个是字节数组,另一个对空结构体取地址即可。
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name interface{}
Tall interface{}
Hobby interface{}
address interface{} //首字母小写
Sex interface{}
Game interface{}
}
func main() {
data := "{\"Name\":\"Tony\",\"Tall\":173.5,\"Hobby\":\"Reading\",\"Sex\":\"男\",\"Game\":{\"Name1\":\"星际争霸\",\"Name2\":\"王者荣耀\"}}"
s := []byte(data)
p := Person{}
err := json.Unmarshal(s, &p)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%T,%#v", p, p)
}
/*
main.Person,main.Person{Name:"Tony", Tall:173.5, Hobby:"Reading", address:interface {}(nil), Sex:"男", Game:map[string]interface {}{"Name1":"星际争霸", "Name2":"王者荣耀"}}
*/
我们通过反射看下它们各自的数据类型:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Person struct {
Name interface{}
Tall interface{}
Hobby interface{}
address interface{} //首字母小写
Sex interface{}
Game interface{}
}
func main() {
data := "{\"Name\":\"Tony\",\"Tall\":173.5,\"Hobby\":\"Reading\",\"Sex\":\"男\",\"Game\":{\"Name1\":\"星际争霸\",\"Name2\":\"王者荣耀\"}}"
s := []byte(data)
p := Person{}
printType(&p)
err := json.Unmarshal(s, &p)
if err != nil {
fmt.Println(err)
}
fmt.Println("Unmarshal之后的结果")
printType(&p)
}
func printType(p *Person) {
nameType := reflect.TypeOf(p.Name)
tallType := reflect.TypeOf(p.Tall)
hobbyType := reflect.TypeOf(p.Hobby)
addressType := reflect.TypeOf(p.address)
sexType := reflect.TypeOf(p.Sex)
gameType := reflect.TypeOf(p.Game)
fmt.Println("nameType:", nameType)
fmt.Println("ageType:", tallType)
fmt.Println("highType:", hobbyType)
fmt.Println("sexType:", addressType)
fmt.Println("classType:", sexType)
fmt.Println("testType:", gameType)
}
/*
nameType: <nil>
ageType: <nil>
highType: <nil>
sexType: <nil>
classType: <nil>
testType: <nil>
Unmarshal之后的结果
nameType: string
ageType: float64
highType: string
sexType: <nil>
classType: string
testType: map[string]interface {}
*/
最后还可以指定别名,大家可以试下:
Name string `json:"name"`
这个就是用name代替Name