结构体

数组可以存储同一类的数据,但在结构体中,我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体的定义格式:
type 类型名 struct {
    成员属性1 类型1
    成员属性2 类型2
    成员属性3 成员属性4 类型3
    ...
}
类型名,表示结构体的名称,在同一个包内不能重复。
结构体中的属性,也叫字段必须唯一。
同类型的成员属性可以写在一行。

type teacher struct {
	name string
	age  int8
	sex  byte
}

结构体的定义只是一种内存布局的描述,只有当结构体实例化了,才会真正分配内存。
必须在实例化后才能使用结构体。
实例化就是根据结构体定义的格式创建一份与格式一致的内存区域。
结构体实例之间的内存是完全独立的。

先声明一个print函数,方便输入后面的代码。

func printTeacher(t teacher) {
	fmt.Printf("姓名:%v,年龄:%d,性别%v  \n", t.name, t.age, t.sex)
}

声明一个结构体,并打印信息。

var t0 teacher
printTeacher(t0)

var格式声明方式实例化结构体。

var t1 teacher
t1.name = "t1"
t1.age = 30
t1.sex = 0
printTeacher(t1)

短变量声明格式实例化结构体。

t2 := teacher{}
t2.name = "t2"
t2.age = 35
t2.sex = 1
printTeacher(t2)

用简短声明格式实例化结构体,并初始化。

t3 := teacher{
	"t3",
	40,
	1,
}
printTeacher(t3)
t4 := teacher{"t4", 50, 0}
printTeacher(t4)

创建指针类型的结构体:
使用内置函数new()对结构体进行实例化,结构体实例化后形成的指针类型的结构体。
new函数会分配内存,第一个采纳数是类型,而不是值,返回的值是指向该类型新分配的零值指针。
盖函数用于创建某个类型的指针。

t5 := new(teacher)
//标准写法
(*t5).name = "t5"
(*t5).age = 55
//简化写法(语法糖)
t5.sex = 1
printTeacher(*t5)

结构体是一个值类型:

func testNewClass2() {
	t1 := teacher{"t1", 21, 1}
	fmt.Printf("t1 : %T , %v , %p \n", t1, t1, &t1)
	fmt.Println("--------------")
	t2 := t1
	t2.name = "t2"
	t2.age = 22
	fmt.Printf("t1 : %T , %v , %p \n", t2, t2, &t2)
	fmt.Printf("t1 : %T , %v , %p \n", t1, t1, &t1)
}

结构体是一个值类型,属于深拷贝,可以引用结构体的地址来进行浅拷贝。

func testClass3() {
	t1 := teacher{"t1", 10, 1}
	fmt.Printf("t1的姓名:%v,t1的年龄:%v,t1的性别:%v \n", t1.name, t1.age, t1.sex)
	//深拷贝
	t2 := t1
	t2.name = "t2"
	t2.age = 20
	t2.sex = 0
	fmt.Printf("t2的姓名:%v,t2的年龄:%v,t2的性别:%v \n", t2.name, t2.age, t2.sex)
	fmt.Printf("修改t2后t1的姓名:%v,t1的年龄:%v,t1的性别:%v \n", t1.name, t1.age, t1.sex)
	fmt.Println("---------------------------------")

	//浅拷贝
	t3 := &t1
	t3.name = "t3"
	t3.age = 30
	t3.sex = 0
	fmt.Printf("t2的姓名:%v,t2的年龄:%v,t2的性别:%v \n", t3.name, t3.age, t3.sex)
	fmt.Printf("修改t2后t1的姓名:%v,t1的年龄:%v,t1的性别:%v \n", t1.name, t1.age, t1.sex)
	fmt.Println("---------------------------------")
}

将结构体作为函数参数

func testClass4(t teacher) {
	t.name = "修改以后"
	t.age = 99
	t.sex = 0
	printTeacher(t)
}

将结构体指针作为函数参数

func testClass5(t *teacher) {
	t.name = "修改以后"
	t.age = 99
	t.sex = 0
	printTeacher(*t)
}

将结构体作为返回值

func testClass6(t teacher) teacher {
	t.name = "修改以后"
	t.age = 99
	t.sex = 0
	return t
}

将结构体指针作为返回值

func testClass7(t teacher) *teacher {
	t.name = "修改以后"
	t.age = 99
	t.sex = 0
	return &t
}

 

匿名结构体
没有名字的结构体。
无需通过type关键字定义就能直接使用。
在创建匿名结构体时,同时需要创建对象。
匿名结构体由结构体定义和兼职对初始化两个部分组成。
一般情况下匿名结构体仅仅只使用1次。
语法格式:
变量名 := struct {
    定义成员属性
} { 初始化成员属性 }

匿名结构体示例:

func anonymousStruct1() {
	addr := struct {
		province, city string
	}{"HuBei", "WuHan"}
	fmt.Println(addr) //{HuBei WuHan}
}

匿名字段
结构体中的字段没有名字,只包含一个没有字段名的类型。
如果字段没有名字,那么默认使用类型作为字段名。
同一个类型只能写一个,局限性比较强。
结构体嵌套中采用的匿名结构体字段可以模拟继承关系。

匿名字段示例:

type cat struct {
	string
	int8
	byte
}

func anonymousVariables1() {
	c1 := cat{"mimi", 5, 0}
	fmt.Println(c1)
	//分别输出
	fmt.Printf("名字:%v , 年龄:%v ,性别:%v \n", c1.string, c1.int8, c1.byte)
}