Go语言进阶,结构体与json字符串格式的互相转换

        对于结构体大家都很熟悉,是一种自定义类型,可以将不同类型的同属于这个类的属性(成员变量)集合在一起,换句话说这些成员变量属于键值对,那么这种也就是常见的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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寅恪光潜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值