Golang语言学习笔记(九)

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
	}

}
原文地址:https://www.cnblogs.com/hanajiang/p/13787229.html