Golang中的复合数据类型
4.结构体
1).关于Golang结构体
Golang中没有类的概念,Golang中的结构体和其他语言中的类有点相似。和其他面向对象语言中的类相比,Golang中的结构体具有更高的扩展性和灵活性
Golang中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,再使用但是的基本数据类型就无法满足需求了,Golang中提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。我们可以通过struct来定义自己的类型。
2).Golang type关键字自定义类型和类型别名
Golang中通过type关键字定义一个结构体
自定义类型
在Go语言中有一些基本的数据类型,如string、整型、浮点型、布尔等数据类型,Go语言中可以使用type关键字来定义自定义类型。
type myInt int
上面代码表示:将myInt定义为int类型,通过type关键字的定义,myInt就是一种新的类型,它具有int的特性。
类型别名
Golang1.9版本以后添加的新功能
类型别名规定:TypeAlias只是Type的别名,本质是TypeAlias与Type是同一个类型。
type TypeAlias = Type
3).结构体定义初始化的几种方法
结构体的定义
使用type和struct关键字来定义结构体,具体代码格式如下:
type 类型名 struct {
字段名 字段类型
字段名 字段类型
...
}
其中
- 类型名:表示自定义结构体的名称,在同一个包内不能重复
- 字段名:表示结构体字段名,结构体中的字段名必须唯一
- 字段类型:表示结构体字段的具体类型
结构体实例化(第一种方法)
只有当结构体实例化时,才会真正的分配内存,也就是必须实例化后才能使用结构体的字段。
结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型
var 结构体实例 结构体类型
结构体实例化(第二种方法)
我们还可以通过使用new关键字对结构体进行实例化,得到的是结构体的地址
var 结构体实例 = new(结构体类型)
var p2 = new(Person)
p2.name = "lisi"
p2.age = 20
p2.sex = "Male"
注意:在Golang中支持对结构体指针直接使用.来访问结构体的成员。p2.name = "lisi" 其实在底层是(*p2).name = "lisi"
结构体实例化(第三种方法)
使用&对结构体进行取地址操作相当于对该结构体类型进行了一次new实例化操作
结构体实例化(第四种方法)
键值对初始化
var 结构体实例 = 结构体类型{
结构体属性: 属性对应值,
结构体属性: 属性对应值,
...
}
注意,最后一个属性的逗号(,)要加上
结构体实例化(第五种方法)
结构体指针进行键值对初始化
var 结构体实例 = &结构体类型{
结构体属性: 属性对应值,
结构体属性: 属性对应值,
...
}
当某些字段没有初始值的时候,这个字段可以不写。此时,没有指定初始值的字段的值为类型零值
结构体实例化(第六种方法)
使用值的列表初始化
初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值:
结构体实例 := &结构体类型{
属性值,
属性值,
...
}
4).结构体方法和接收者
在Go语言中给,没有类的概念但是可以给类型(结构体,自定义类型)定义方法。所谓方法就是定义了接收这的函数。接收者的概念就类似于其他语言中的this或者self。
方法的定义格式如下:
func (接收者变量 接收者类型) 方法名(参数列表)(返回参数){
函数体
}
其中
- 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母,而不是self、this之类的命名。列如,Person类型的接收者变量应该命名为p,Connector类型的接收者变量名应该命名为c等。
- 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
- 方法名、参数列表、返回参数:具体格式与函数定义相同。
5).给任意类型添加方法
在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。
6).结构体的匿名字段
结构体允许其成员变量在声明是没有字段名只有类型,这种没有字段名字的字段就称为匿名字段
7).嵌套结构体
结构体的字段类型可以是:基本数据类型,也可以是切片、map 以及结构体
如果结构体的字段类型是:指针、slice、和map的零值都是nil,即还没有分配空间
如果需要使用这样的字段,就要先make,才能使用
8).嵌套匿名结构体
注意:当访问结构体成员时,会先在结构体中查找该字段,找不到再去匿名结构体中查找。
9).关于嵌套结构体的字段名冲突
嵌套结构体内部可能存在相同的字段名。这个时候为了避免歧义,需要指定具体的内嵌结构体的字段
10).结构体的继承
Go语言中使用结构体也可以实现其他编程语言中的继承
一个结构体中可以嵌套包含另一个结构体或者结构体指针
Golang结构体和Json相互转换 序列化 反序列化
1.关于JSON数据
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。RESTful API 接口中返回的数据都是json数据
2.结构体与JSON序列化
如果Golang要给App或者小程序提供API接口数据,就需要涉及到结构体和json之间的相互转换
Golang JSON序列化是指把结构体数据转化成JSON格式的字符串,Golang JSON 的反序列化是指把JSON数据转化成Golang中的结构体对象
Golang中的序列化和反序列化主要通过"encoding/json"包中的json.Marshal()和json.Unmarshal()方法实现。
3.结构体标签Tag
Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:
`key1:"value1" key2:"value2"`
结构体tag由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。同一个结构体字段可以设置多个键值对tag,不同的键值对之间使用空格分隔。
注意事项:为结构体编写tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误信息,通过反射也无法正确取值。例如不要再key和value之间添加空格。
4.嵌套结构体和JSON序列化反序列化
4.关于Map、切片的序列化反序列化
Map和切片也可以进行序列化和反序列化,在学习接口之后再详细学习。
代码:
package main
import (
"fmt"
"encoding/json"
)
//自定义类型
type MyInt int
//注意:非本地类型不能定义方法,也就是不能给别的包的类型定义方法
func (m MyInt) PrintInfo() {
fmt.Println("我是自定义类型的自定义方法")
}
type myFn func(int, int) int
//类型别名
type myFloat = float64
//注意:结构体首字母可以大写也可以小写,大写表示这个结构体是公有的,在其他的包里面可以使用,小写表示这个结构体是私有的,只有这个包里面才能使用
type Person struct {
name string
age int
sex string
}
func (p Person) PrintInfo() {
fmt.Printf("name:%v, age:%v", p.name, p.age)
}
//想要修改结构体的属性值,接收体类型必须是结构体指针
func (p *Person) SetInfo(name string, age int) {
p.name = name
p.age = age
}
type Student struct {
name string
age int
sex string
}
/*
结构体的匿名字段:
结构体允许其成员变量在声明是没有字段名只有类型,这种没有字段名字的字段就称为匿名字段
匿名字段默认采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个
*/
type Teacher struct {
string
int
}
/*
嵌套结构体
结构体的字段类型可以是:基本数据类型,也可以是切片、map 以及结构体
如果结构体的字段类型是:指针、slice和map的零值都是nil,即还没有分配空间
如果需要使用这样的字段,就要先make,才能使用
*/
type Driver struct {
Name string
Age int
Hobby []string
map1 map[string]string
}
type User struct {
Username string
Password string
Address Address //User结构体嵌套Address结构体
}
type Address struct {
Name string
Phone string
City string
}
/*
嵌套匿名结构体
*/
type Customer struct {
Username string
Password string
Address
}
//嵌套结构体的字段名冲突
type Client struct {
Username string
Password string
Addtime string
Contact
}
type Contact struct {
Name string
Phone string
City string
Addtime string
}
type Employee struct {
Username string
Password string
Contact
Email
}
type Email struct {
Account string
Addtime string
}
//结构体的继承
//一个结构体中可以嵌套包含另一个结构体或者结构体指针
//父结构体
type Animal struct {
Name string
}
func (a Animal) run(){
fmt.Printf("%v 在运动
", a.Name)
}
//子结构体
type Dog struct{
Age string
Animal //结构体嵌套 继承
}
func (d Dog) shout(){
fmt.Printf("%v 在旺旺
", d.Name)
}
type Cat struct{
Age string
*Animal //结构体嵌套 继承
}
func (c Cat) shout(){
fmt.Printf("%v 在旺旺
", c.Name)
}
//json序列化
type Professor struct {
ID int `json:"id"` //通过指定tag实现json序列化该字段时的key
Gender string `json:"gender"`
// name string//私有属性不能被json包访问
Name string `json:"name"`
Pno string `json:"pno"`
}
type Learner struct {
Id int
Gender string
Name string
}
type Class struct {
Title string
Learners []Learner
}
func main() {
//结构体
//类型别名
// var a myInt = 10
// fmt.Printf("%v %T
", a, a)//10 main.myInt
// var b myFloat = 10.3
// fmt.Printf("%v %T
", b, b)//10。3 float64
//
// var p1 Person //实例化Person结构体
// p1.name = "zhangsan"
// p1.age = 20
// p1.sex = "Male"
// fmt.Printf("值:%v 类型:%T
", p1, p1)//值:{zhangsan 20 Male} 类型:main.Person
// //使用%#v打印结构体具体信息
// fmt.Printf("值:%#v 类型:%T", p1, p1)//值:main.Person{name:"zhangsan", age:20, sex:"Male"} 类型:main.Person
//注意:在Golang中支持对结构体指针直接使用.来访问结构体的成员。p2.name = "lisi" 其实在底层是(*p2).name = "lisi"
// var p2 = new(Person)
// p2.name = "lisi"
// p2.age = 20
// p2.sex = "Male"
// fmt.Printf("值:%#v 类型:%T
", p2, p2)//值:&main.Person{name:"lisi", age:20, sex:"Male"} 类型:*main.Person
// (*p2).name = "wangwu"
// fmt.Printf("值:%#v 类型:%T
", p2, p2)//值:&main.Person{name:"wangwu", age:20, sex:"Male"} 类型:*main.Person
// var p3 = &Person{}
// p3.name = "zhaoliu"
// p3.age = 23
// p3.sex = "Male"
// fmt.Printf("值:%#v 类型:%T
", p3, p3) //值:&main.Person{name:"zhaoliu", age:23, sex:"Male"} 类型:*main.Person
// var p4 = Person{
// name: "test",
// age: 20,
// sex: "Female",
// }
// fmt.Printf("值:%#v 类型:%T
", p4, p4)//值:main.Person{name:"test", age:20, sex:"Female"} 类型:main.Person
// var p5 = &Person{
// name: "Tom",
// age: 20,
// sex: "Female",
// }
// fmt.Printf("值:%#v 类型:%T
", p5, p5)//值:&main.Person{name:"Tom", age:20, sex:"Female"} 类型:*main.Person
// var p6 = &Person{
// name: "Jerry",
// }
// fmt.Printf("值:%#v 类型:%T
", p6, p6)//值:&main.Person{name:"Jerry", age:0, sex:""} 类型:*main.Person
// var p7 = &Person{
// "hana",
// 25,
// "Female",
// }
// fmt.Printf("值:%#v 类型:%T
", p7, p7)//值:&main.Person{name:"hana", age:25, sex:"Female"} 类型:*main.Person
//结构体方法和接收者
// var s1 = Student {
// name: "ash",
// age: 27,
// sex: "Female",
// }
// s2 := s1
// s2.name = "hana"
// fmt.Printf("%#v
",s1)//main.Student{name:"ash", age:27, sex:"Female"}
// fmt.Printf("%#v
",s2)//main.Student{name:"hana", age:27, sex:"Female"}
// //结构体是值类型
// var p = Person{
// name: "zhangsan",
// age: 20,
// sex: "Male",
// }
// p.PrintInfo()//name:zhangsan, age:20
// fmt.Println()
// var pp = Person{
// name: "lisi",
// age: 20,
// sex: "Male",
// }
// pp.PrintInfo()//name:lisi, age:20
// fmt.Println()
// p.PrintInfo()//name:zhangsan, age:20
//Golang中结构体实例是独立的,不会相互影响
// fmt.Println()
// p.SetInfo("wangwu",11)
// p.PrintInfo()//name:wangwu, age:11
// fmt.Println()
// pp.PrintInfo()//name:lisi, age:20
// var myInt MyInt
// myInt.PrintInfo()
//匿名结构体
// t := Teacher {
// "zhangsan",
// 30,
// }
// fmt.Println(t)//{zhangsan 30}
//嵌套结构体
// var d Driver
// d.Name = "lisi"
// d.Age = 30
// d.Hobby = make([]string, 3, 6)
// d.Hobby[0] = "drive"
// d.Hobby[1] = "sport"
// d.Hobby[2] = "sleep"
// d.map1 = make(map[string]string)
// d.map1["address"] = "beijing"
// d.map1["phone"] = "12345678901"
// // fmt.Printf("%#v",d)//main.Driver{Name:"lisi", Age:30, Hobby:[]string{"drive", "sport", "sleep"}, map1:map[string]string{"address":"beijing", "phone":"12345678901"}}
// fmt.Printf("%v", d.Hobby) //[drive sport sleep]
// var u User
// u.Username = "hana"
// u.Password = "123456"
// u.Address.Name = "zhangsan"
// u.Address.Phone = "12343879609"
// u.Address.City = "chengdu"
// fmt.Printf("%#v", u)//main.User{Username:"hana", Password:"123456", Address:main.Address{Name:"zhangsan", Phone:"12343879609", City:"chengdu"}}
//嵌套匿名结构体
// var c Customer
// c.Username = "hana"
// c.Password = "123456"
// c.Address.Name = "zhangsan"
// c.Address.Phone = "12343879609"
// c.Address.City = "chengdu"
// // fmt.Printf("%#v
", c)//main.Customer{Username:"hana", Password:"123456", Address:main.Address{Name:"zhangsan", Phone:"12343879609", City:"chengdu"}}
// c.City = "ShangHai"//当访问结构体成员时,会先在结构体中查找该字段,找不到再去匿名结构体中查找。
// fmt.Printf("%#v
", c)//main.Customer{Username:"hana", Password:"123456", Address:main.Address{Name:"zhangsan", Phone:"12343879609", City:"ShangHai"}}
// fmt.Println(c.Address.Phone)//12343879609
// fmt.Println(c.Phone)//12343879609
//关于嵌套结构体的字段名冲突
// var c Client
// c.Username = "wangwu"
// c.Password = "123456"
// c.Contact.Name = "zhangsan"
// c.Contact.Phone = "12343879609"
// c.Contact.City = "chengdu"
// c.City = "ShenZhen"
// c.Addtime = "2020-10-09"
// fmt.Printf("%#v
", c)//main.Client{Username:"wangwu", Password:"123456", Addtime:"2020-10-09", Contact:main.Contact{Name:"zhangsan", Phone:"12343879609", City:"ShenZhen", Addtime:""}}
// c.Contact.Addtime = "2020-10-10"
// fmt.Printf("%#v
", c)//main.Client{Username:"wangwu", Password:"123456", Addtime:"2020-10-09", Contact:main.Contact{Name:"zhangsan", Phone:"12343879609", City:"ShenZhen", Addtime:"2020-10-10"}}
// var e Employee
// e.Username = "wangwu"
// e.Password = "123456"
// e.Contact.Name = "zhangsan"
// e.Contact.Phone = "12343879609"
// e.Contact.City = "chengdu"
// e.City = "ShangHai"
// // e.Addtime = "2020-10-09"//ambiguous selector e.Addtime
// e.Contact.Addtime = "2020-10-09"
// e.Email.Addtime = "2020-10-10"
// fmt.Printf("%#v
", e)//main.Employee{Username:"wangwu", Password:"123456", Contact:main.Contact{Name:"zhangsan", Phone:"12343879609", City:"ShangHai", Addtime:"2020-10-09"}, Email:main.Email{Account:"", Addtime:"2020-10-10"}}
// var d = Dog{
// Age: "20",
// Animal: Animal{
// Name: "daqing",
// },
// }
// d.run()//daqing 在运动
// d.shout()//daqing 在旺旺
var c = Cat{
Age: "20",
Animal: &Animal{
Name: "weiwei",
},
}
c.run()//weiwei 在运动
c.shout()//weiwei 在旺旺
//结构体转json
// var p1 = Professor{
// ID: 11,
// Gender: "Male",
// Name: "Tom",
// Pno: "p0001",
// }
// fmt.Printf("%#v
",p1)//main.Professor{ID:11, Gender:"Male", Name:"Tom", Pno:"p0001"}
// var jsonByte, _ = json.Marshal(p1)
// jsonStr := string(jsonByte)
// fmt.Printf("%v",jsonStr)//{"ID":11,"Gender":"Male","Name":"Tom","Pno":"p0001"}
//json转结构体
// var str = `{"ID":11,"Gender":"Male","Name":"Tom","Pno":"p0001"}`
// var p2 Professor
// err := json.Unmarshal([]byte(str), &p2)
// if err != nil {
// fmt.Println(err)
// }
// fmt.Printf("%#v
", p2) //main.Professor{ID:11, Gender:"Male", Name:"Tom", Pno:"p0001"}
// fmt.Println(p2.Name) //Tom
//结构体标签
// var p3 = Professor{
// ID: 11,
// Gender: "Male",
// Name: "Tom",
// Pno: "p0001",
// }
// var jsonByte, _ = json.Marshal(p3)
// jsonStr := string(jsonByte)
// fmt.Printf("%v",jsonStr)//{"id":11,"gender":"Male","name":"Tom","pno":"p0001"}
//嵌套结构体和JSON序列化反序列化
// c := Class{
// Title: "001",
// Learners: make([]Learner, 0, 200),
// }
// for i := 0; i < 10; i++ {
// l := Learner{
// Id: i,
// Gender: "Male",
// Name: fmt.Sprintf("learn_%v", i),
// }
// c.Learners = append(c.Learners, l)
// }
// fmt.Printf("%#v
", c) //main.Class{Title:"001", Learners:[]main.Learner{main.Learner{Id:0, Gender:"Male", Name:"learn_0"}, main.Learner{Id:1, Gender:"Male", Name:"learn_1"}, main.Learner{Id:2, Gender:"Male", Name:"learn_2"}, main.Learner{Id:3, Gender:"Male", Name:"learn_3"}, main.Learner{Id:4, Gender:"Male", Name:"learn_4"}, main.Learner{Id:5, Gender:"Male", Name:"learn_5"}, main.Learner{Id:6, Gender:"Male", Name:"learn_6"}, main.Learner{Id:7, Gender:"Male", Name:"learn_7"}, main.Learner{Id:8, Gender:"Male", Name:"learn_8"}, main.Learner{Id:9, Gender:"Male", Name:"learn_9"}}}
// strByte, err := json.Marshal(c)
// if err != nil {
// fmt.Println(err)
// } else {
// strJson := string(strByte)
// fmt.Println(strJson)//{"Title":"001","Learners":[{"Id":0,"Gender":"Male","Name":"learn_0"},{"Id":1,"Gender":"Male","Name":"learn_1"},{"Id":2,"Gender":"Male","Name":"learn_2"},{"Id":3,"Gender":"Male","Name":"learn_3"},{"Id":4,"Gender":"Male","Name":"learn_4"},{"Id":5,"Gender":"Male","Name":"learn_5"},{"Id":6,"Gender":"Male","Name":"learn_6"},{"Id":7,"Gender":"Male","Name":"learn_7"},{"Id":8,"Gender":"Male","Name":"learn_8"},{"Id":9,"Gender":"Male","Name":"learn_9"}]}
// }
str := `{"Title":"001","Learners":[{"Id":0,"Gender":"Male","Name":"learn_0"},{"Id":1,"Gender":"Male","Name":"learn_1"},{"Id":2,"Gender":"Male","Name":"learn_2"},{"Id":3,"Gender":"Male","Name":"learn_3"},{"Id":4,"Gender":"Male","Name":"learn_4"},{"Id":5,"Gender":"Male","Name":"learn_5"},{"Id":6,"Gender":"Male","Name":"learn_6"},{"Id":7,"Gender":"Male","Name":"learn_7"},{"Id":8,"Gender":"Male","Name":"learn_8"},{"Id":9,"Gender":"Male","Name":"learn_9"}]}`
var c = &Class{}
err := json.Unmarshal([]byte(str),c)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%#v
",c)//&main.Class{Title:"001", Learners:[]main.Learner{main.Learner{Id:0, Gender:"Male", Name:"learn_0"}, main.Learner{Id:1, Gender:"Male", Name:"learn_1"}, main.Learner{Id:2, Gender:"Male", Name:"learn_2"}, main.Learner{Id:3, Gender:"Male", Name:"learn_3"}, main.Learner{Id:4, Gender:"Male", Name:"learn_4"}, main.Learner{Id:5, Gender:"Male", Name:"learn_5"}, main.Learner{Id:6, Gender:"Male", Name:"learn_6"}, main.Learner{Id:7, Gender:"Male", Name:"learn_7"}, main.Learner{Id:8, Gender:"Male", Name:"learn_8"}, main.Learner{Id:9, Gender:"Male", Name:"learn_9"}}}
fmt.Println(c.Title)//001
}
}