结构体
结构体的基本概念
- 什么是结构体
- Go语言中的结构体几乎和C语言中的结构体一模一样都需要先定义结构体类型, 再定义结构体变量都是用来保存一组不同类型数据的
- 定义结构体类型格式:
type 结构体类型名称 struct{
属性名称 属性类型;
属性名称 属性类型;
} - 定义结构体变量格式:
var 结构体变量名称 结构体类型名称
结构体初始化
注意点:
和切片以及字典不一样, 结构体变量定义之后就可以直接使用了
//1.定义一个结构体
//1.1定义结构体类型
type Person struct {
name string
age int
}
//1.2定义结构体变量(先定义后初始化)
var per Person
//1.3操作结构体
//切片和字典定义变量后必须初始化才能使用
//结构体变量定义完成后不需要初始化可以直接使用
per.name = "lnj"
per.age = 18
fmt.Println(per)
- 先定义结构体变量再初始化
//3.先定义结构体变量再初始化
//定义结构体类型
type Person struct {
name string
age int
}
//定义结构体变量
var per Person
//给结构体完全初始化
per = Person{"wjh",19}
//给结构体部分初始化
//注意点: 部分初始化必须通过属性名称指定要给谁初始化
per = Person{age : 18}
fmt.Println(per)
- 定义结构体变量的同时初始化
//2.定义结构体变量一次性初始化
//定义一个结构体类型
type Person struct {
name string
age int
}
//定义结构体变量一次性初始化
var per Person = Person{"lnj",18}
//结构体变量名称后面可以省略结构体类型
var per = Person{"lnj",18}
//可以使用语法糖来定义同时一次性初始化
per := Person{"lnj",18}
fmt.Println(per)
结构体值传递
package main
import "fmt"
//定义一个结构体
type Person struct {
name string
age int
}
func main() {
/*
结构体和数组一样,都是值传递
作为函数的参数,在函数内部修改值不会影响到外面实参的值
*/
per1 := Person{"wjh", 19}
var per2 Person
//将结构体变量per1的值传递给per2
per2 = per1
per2.name = "lnj"
fmt.Println(per1)//{wjh 19}
//修改结构体变量per2的值不会影响per1中的值
fmt.Println(per2)//{lnj 19}
per := Person{"lnj", 10}
//结构体作为函数的参数,在函数内部修改值不会影响到外面实参的值
change(per)
fmt.Println(per)
}
func change(per Person) {
per.name = "haha"
}
复杂结构体
package main
import "fmt"
func main() {
/*
复杂的结构体
*/
type Person struct {
name string //字符串
age int //整型
score float64 //浮点型
arr [3]int //数组类型
sce []int //切片类型
dict map[string]string //字典类型
}
//普通类型结构体属性都可以直接操作,不需要初始化
var per Person
per.name = "lnj"
per.age = 18
per.score = 80.5
per.arr[0] = 10
per.arr[1] = 20
per.arr[2] = 30
//{lnj 18 80.5 [10 20 30] [] map[]}
//切片和字典类型的必须要先初始化才可以使用
//创建切片
//per.sce = []int{10,20,30}
//注意点: 使用索引方式,不能超过切片的长度
per.sce = make([]int,3)
per.sce[0]= 10
per.sce[1]= 20
per.sce[2]= 30
//创建字典
per.dict = make(map[string]string,2)
per.dict["name"] = "wjh"
per.dict["age"] = "18"
//per.dict = map[string]string{"name":"wjh","age" :"18"}
fmt.Println(per)
}
结构体转换
注意点:
结构体变量之间可以相互转换, 但是必须保证结构体类型的属性名称 属性类型 属性顺序 属性的个数 都一样
package main
import "fmt"
func main() {
/*
结构体变量之间可以相互转换, 但是必须保证结构体类型的
属性名称 属性类型 属性顺序 属性的个数 都一样
*/
type Person1 struct {
name string
age int
}
//属性顺序不同
type Person2 struct {
age int
name string
}
//属性名称不同
type Person3 struct {
name string
score int
}
//属性类型不同
type Person4 struct {
name string
score float64
}
//属性的个数不同
type Person5 struct {
name string
age int
score float64
}
//属性顺序不同不能强转
//var per2 Person2
//per2 = Person1(per2)
//fmt.Println(per2)
//属性名称不同不能强转
//var per3 Person3
//per3 = Person1(per3)
//fmt.Println(per3)
//属性类型不同不能强转
var per4 Person4
per4 = Person1(per4)
fmt.Println(per4)
//属性个数不同不能强转
var per5 Person5
per5 = Person1(per5)
fmt.Println(per5)
}
匿名结构体
- 什么是匿名结构体属性?
没有名称的属性就是匿名属性 - 如何操作匿名属性?
匿名属性的数据类型就是匿名属性的名称, 所以可以通过匿名属性的数据类型来操作 - 匿名属性一般都用于结构体的嵌套定义,结构体的属性又是一个结构体
package main
import "fmt"
func main() {
type Person struct {
string //匿名结构体属性
int
}
var per Person
per.string = "wjh" //可以通过匿名属性的数据类型来操作
per.int = 18
fmt.Println(per)
type Date struct {
year int
month int
day int
}
type Person struct {
name string
age int
Date //结构体嵌套定义
}
type Animal struct {
name string
age int
Date
}
//使用结构体嵌套
var per Person
per.name = "wjh"
per.age = 19
per.Date = Date{2007,10,23} //{wjh 19 {2007 10 23}}
fmt.Println(per)
//定义结构体变量同时直接初始化
ani := Animal{"wawa",10,Date{2003,10,23}}
fmt.Println(ani)//{wawa 10 {2003 10 23}}
}
结构体嵌套的方式
-
第一种方式(双重嵌套)
type 结构体名称1 struct{}
type 结构体名称2 struct{
结构体名称1
}
//1.第一种方式
// 结构体和嵌套的结构体没有重名属性的情况
type Person struct {
name string
age int
}
type Student struct {
Person
score float64
}
//定义同时初始化结构体
stu := Student{Person{"wjh", 19}, 86.6}
fmt.Println(stu)
////1.1结构体嵌套定义,第一种操作结构体方法
//stu.Person.name = "lnj"
//stu.Person.age = 30
//fmt.Println(stu)
//1.2第二种操作结构体方法
//会先去Student结构体中查询有没有name属性, 如果有就直接访问
//如果没有会继续查找嵌套的匿名结构体中有没有, 如果有就访问匿名结构体中的name属性
stu.name = "zs" //嵌套结构体属性不重名可以直接访问
stu.age = 20
fmt.Println(stu)
//2.第一种方式有重名属性的情况
//结构体和嵌套的结构体有重名属性的情况
type Person struct {
name string
age int
}
type Student struct {
Person
name string
score float64
}
//定义同时初始化结构体
stu := Student{Person{"wjh",19},"lnj", 90.3}
fmt.Println(stu) //{{wjh 19} lnj 90.3}
//2.1结构体嵌套定义,操作结构体的第一种方法
//注意点: 如果结构体与嵌套的结构体属性有重名,使用这种方法操作数据,不会更改嵌套结构体中的同名属性
stu.name = "haha"
fmt.Println(stu) //{{wjh 19} haha 90.3}
//2.2结构体嵌套定义,操作结构体第二种方法
//注意点: 如果结构体与嵌套的结构体属性有重名,应该先指定结构体类型在指定结构体属性
stu.Person.name = "zs"
stu.age = 30
fmt.Println(stu) //{{zs 30} haha 90.3}
- 第二种方式(三重嵌套)
type 结构体名称1 struct{
}
type 结构体名称2 struct{
结构体名称1
}
type 结构体名称3 struct{
结构体名称2
}
//第二种方式
//1.没有重名属性
type Object struct {
name string
}
type Person struct {
Object
age int
}
type Student struct {
Person
score float32
}
//定义变量同时初始化
stu := Student{Person{Object{"wjh"}, 19}, 87.3}
fmt.Println(stu) //{{{wjh} 19} 87.3}
//操作结构体第一种方法
stu.name = "zs"
stu.age = 30
stu.score = 50.3
fmt.Println(stu) //{{{zs} 30} 50.3}
//操作结构体第二种方法
stu.Person.Object.name = "lnj"
stu.Person.age = 50
fmt.Println(stu) //{{{lnj} 50} 50.3}
//有重名属性的情况
type Object struct {
name string
}
type Person struct {
Object
name string
age int
}
type Student struct {
Person
name string
score float32
}
//定义变量同时初始化
stu := Student{Person{Object{"wjh"},"lnj",13},"niuzi",39.2}
fmt.Println(stu) //{{{wjh} lnj 13} niuzi 39.2}
//操作结构体方法
//注意点: 如果不先指定结构体类型,只会操作最外面结构体的对应的重名属性
stu.name = "whaha" //修改Student结构体类型的name属性
stu.Person.name = "zs" //修改Person结构体类型的name属性
stu.Person.Object.name = "lili" //修改Object结构体类型的name属性
fmt.Println(stu) //{{{lili} zs 13} whaha 39.2}
-
第三种方式
type 结构体名称1 struct{}
type 结构体名称2 struct{
}
type 结构体名称3 struct{
结构体名称1
结构体名称2
}
//第三种方式
//没有重名属性情况
type Object struct {
name string
}
type Person struct {
age int
}
type Student struct {
Object
Person
score float64
}
//定义变量同时初始化
stu := Student{Object{"lnj"},Person{19},30.6}
fmt.Println(stu) //{{lnj} {19} 30.6}
//操作结构体属性
stu.Person.age = 30
stu.Object.name = "wjh"
fmt.Println(stu) //{{wjh} {30} 30.6}
//有重名属性的情况
type Object struct {
name string
}
type Person struct {
name string
age int
}
type Student struct {
Object
Person
name string
score float64
}
stu := Student{Object{"haha"},Person{"lnj", 19},"wjh", 30.5}
fmt.Println(stu)
//操作结构体属性
stu.name = "ll"
stu.Person.name = "zz"
stu.Object.name = "kk"
fmt.Println(stu)
结构体嵌套定义注意点
- 结构体的属性类型不能是当前结构体的类型(不能自己嵌套自己)
- 只有匿名属性才会向上查找, 非匿名属性不会向上查找
package main
import "fmt"
func main() {
/*
1.结构体的嵌套定义的注意点:
1.1结构体的属性类型不能是当前结构体的类型
1.2只有匿名属性才会向上查找, 非匿名属性不会向上查找
*/
type Person struct {
//Person 结构体属性不能是自己本身的结构体类型
name string
age int
}
type Student struct {
//per Person //非匿名结构体属性
Person //匿名结构体属性
score float32
}
stu := Student{Person{"wjh", 18}, 52.3}
fmt.Println(stu)
//匿名结构体属性会自动往匿名结构体查找属性
//非匿名结构体属性使用这种方法查找会报错
fmt.Println(stu.name)
fmt.Println(stu.age)
}