1.1 什么是结构体
结构体也就是类似java中的类,是一种由一系列具有相同类型或不同类型的数据构成的数据集合
1.2 结构体定义
type struct_variable_type struct {
member definition;
member definition;
...
member definition;
}
// 一旦定义了结构体类型,它就能用于变量的声明
variable_name := structure_variable_type {value1, value2...valuen}
示例:
type User struct {
name string
age int
sex byte
}
func main() {
// 按照顺序进行初始化
p1 := User{"ada", 19, 'F'}
fmt.Println(p1)
// 按照field:value进行初始化,这样可以任意顺序
p2 := User{
age: 24,
sex: 'M',
name: "zled",
}
fmt.Println(p2)
//new方式,未设置初始值的,会赋予类型的默认初始值
p3 := new(User)
p3.name = "zzled"
p3.sex = 'M'
fmt.Println(p3)
// 普通定义,分别设置
var p4 User
p4.sex = 'F'
p4.age = 18
p4.name = "ada"
fmt.Println(p4)
}
/*
{ada 19 70}
{zled 24 77}
&{zzled 0 77}
{ada 18 70}
*/
1.3 结构体的访问
直接通过对象名.field进行访问即可
p1 := User{"ada", 19, 'F'}
fmt.Println(p1.name)
/*
ada
*/
1.4 结构体指针
用法与普通指针相同,可以查看上一节的函数指针使用。
type User struct {
name string
age int
sex byte
}
func main() {
u := User{"ada", 19, 'F'}
fmt.Println(u)
structPointer(&u)
}
/*结构体指针*/
func structPointer(u *User) {
fmt.Println("指针所指变量的地址是: ", u)
fmt.Println("指针所指变量的值是: ", *u)
fmt.Printf("%T\n", u)
fmt.Printf("%s\n", u.name)
fmt.Printf("%d\n", u.age)
fmt.Printf("%c\n", u.sex)
}
/*
{ada 19 70}
指针所指变量的地址是: &{ada 19 70}
指针所指变量的值是: {ada 19 70}
*main.User
ada
19
F
*/
1.5 匿名字段(继承字段)
可以用字段来创建结构,这些字段只包含一个没有字段名的类型。这些字段被称为匿名字段。
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // 匿名字段,那么默认Student就包含了Human的所有字段
speciality string
}
func main() {
s := Student{
Human: Human{"ada", 19, 45},
speciality: "resident Evil",
}
fmt.Println(s)
fmt.Println(s.name)
fmt.Println(s.age)
fmt.Println(s.weight)
fmt.Println(s.speciality)
}
/*
{{ada 19 45} resident Evil}
ada
19
45
resident Evil
*/
可以使用”.”的方式进行调用匿名字段中的属性值 实际就是字段的继承
1.6 结构体嵌套
一个结构体可能包含一个字段,而这个字段反过来就是一个结构体。这些结构被称为嵌套结构。
示例:
type Address struct {
city, state string
}
type Person struct {
name string
age int
address Address
}
func main() {
var p Person
p.name = "ada"
p.age = 21
p.address = Address{
city: "Chicago",
state: "Illinois",
}
fmt.Println("Name:", p.name)
fmt.Println("Age:", p.age)
fmt.Println("City:", p.address.city)
fmt.Println("State:", p.address.state)
}
/*
Name: ada
Age: 21
City: Chicago
State: Illinois
*/
1.7 提升字段
在结构体中属于匿名结构体的字段被称为提升字段,因为它们可以被访问,就好像他们属于拥有匿名结构字段的结构一样。理解这个定义是相当复杂的。
type Address struct {
city, state string
}
type Person struct {
name string
age int
Address // 注意与1.6例子的区别
}
func main() {
var p Person
p.name = "ada"
p.age = 21
p.Address = Address{ // 注意与1.6例子的区别
city: "Chicago",
state: "Illinois",
}
fmt.Println("Name:", p.name)
fmt.Println("Age:", p.age)
fmt.Println("City:", p.city) // 注意与1.6例子的区别
fmt.Println("State:", p.state) // 注意与1.6例子的区别
}
/*
Name: ada
Age: 21
City: Chicago
State: Illinois
*/
1.9 结构体比较
结构体是值类型,如果每个字段都具有可比性,则是可比较的,如果他们对应的字段相等,则认为两个结构体变量是相等的。
示例:
type Person struct {
name string
age int
}
func main() {
var p1 Person
p1.name = "ada"
p1.age = 21
var p2 Person
p2.name = "ada"
p2.age = 21
var p3 Person
p3.name = "lion"
p3.age = 20
fmt.Println(p1 == p2)
fmt.Println(p2 == p3)
fmt.Println(p1 == p3)
}
/*
true
false
false
*/
1.8 结构体作为函数参数
1.9 make()和new()的区别
看起来没有区别,都是在堆上分配内存,但它们的行为不同,适用于不同的类型。
- new(T) 为每个新的类型T分配一片内存,初始化为0并且返回类型为*T的内存地址:这种方法返回一个指向类型为T,值为0的地址的地址,它适用于值类型如:数组和结构体;它相当于&T{}。
- make(T) 返回一个类型为T的初始值,它只适用于3种内建的引用类型:slice、map和channel。
换言之,new函数分配内存,make函数初始化。
第一幅图中:
var p *[]int = new([]int) // *p == nil; with len and cap 0
p := new([]int)
第二幅图中:
p :=make([]int,0)
切片已经被初始化,但是指向一个空的数组。
以上两种方式实用性都不高。下面的方法比较实用:
var a []int = make([]int,10,50)
b := make([]int,10,50)
这样分配一个有50个int值的数组,并且创建一个长度为10,容量为50的切片v,该切片指向数组的前10个元素。
// 如果只有一个参数,那么长度和容量相同
v := make([]int, 10)
fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))
// 如果数字有两个,则第一个是长度,第二个是容量,且必须长度小于等于容量
b := make([]int, 10, 50)
fmt.Printf("长度为%d,容量为%d\n", len(b), cap(b))
/*
长度为10,容量为10
长度为10,容量为50
*/
初始完成后,会动态进行调整。
v := make([]int, 3, 5)
fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))
b := [4]int{1, 2, 3, 4}
v = b[:]
fmt.Println(v)
fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))
d := [6]int{1, 2, 3, 4, 5, 6}
v = d[:]
fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))
/*
长度为3,容量为5
[1 2 3 4]
长度为4,容量为4
长度为6,容量为6
*/
获取长度和容量
v := make([]int, 3, 5)
fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))
d := [5]int{1, 2, 3, 4, 5}
v = d[1:4]
fmt.Println(v)
fmt.Printf("长度为%d,容量为%d\n", len(v), cap(v))
/*
长度为3,容量为5
[2 3 4]
长度为3,容量为4
*/