Go 结构体

Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

1 结构体操作

1.1 定义结构体

1
2
3
4
5
6
type struct_variable_type struct {
member definition;
member definition;
...
member definition;
}

一旦定义了结构体类型,它就能用于变量的声明

1
variable_name := structure_variable_type {value1, value2...valuen}

1.2 初始化结构体

1
2
3
4
5
6
7
// 1.按照顺序提供初始化值
P := person{"Tom", 25}
// 2.通过field:value的方式初始化,这样可以任意顺序
P := person{age:24, name:"Tom"}
// 3.new方式,未设置初始值的,会赋予类型的默认初始值
p := new(person)
p.age=24

1.3 访问结构体

访问结构体成员(访问结构的各个字段),通过点.操作符用于访问结构的各个字段。

2 结构体指针

1
var struct_pointer *Books
1
struct_pointer = &Book1

以上定义的指针变量可以存储结构体变量的地址。查看结构体变量地址,可以将 & 符号放置于结构体变量前。

使用结构体指针访问结构体成员,使用 “.” 操作符

3 结构体的嵌套

3.1 结构体的匿名字段

可以用字段来创建结构,这些字段只包含一个没有字段名的类型。这些字段被称为匿名字段。

在类型中,使用不写字段名的方式,使用另一个类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // 匿名字段,那么默认Student就包含了Human的所有字段
speciality string
}
func main() {
// 我们初始化一个学生
mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
// 我们访问相应的字段
fmt.Println("His name is ", mark.name)
fmt.Println("His age is ", mark.age)
fmt.Println("His weight is ", mark.weight)
fmt.Println("His speciality is ", mark.speciality)
// 修改对应的备注信息
mark.speciality = "AI"
fmt.Println("Mark changed his speciality")
fmt.Println("His speciality is ", mark.speciality)
// 修改他的年龄信息
fmt.Println("Mark become old")
mark.age = 46
fmt.Println("His age is", mark.age)
// 修改他的体重信息
fmt.Println("Mark is not an athlet anymore")
mark.weight += 60
fmt.Println("His weight is", mark.weight)
}

可以使用”.”的方式进行调用匿名字段中的属性值

实际就是字段的继承

其中可以将匿名字段理解为字段名和字段类型都是同一个

基于上面的理解,所以可以mark.Human = Human{"Marcus", 55, 220}mark.Human.age -= 1

若存在匿名字段中的字段与非匿名字段名字相同,则最外层的优先访问,就近原则

通过匿名访问和修改字段相当的有用,但是不仅仅是struct字段哦,所有的内置类型和自定义类型都是可以作为匿名字段的。

3.2 结构体嵌套

嵌套的结构体
一个结构体可能包含一个字段,而这个字段反过来就是一个结构体。这些结构被称为嵌套结构

3.3 提升字段

在结构体中属于匿名结构体的字段称为提升字段,因为它们可以被访问,就好像它们属于拥有匿名结构字段的结构一样。

4 导出结构体和字段

如果结构体类型以大写字母开头,那么它是一个导出类型,可以从其他包访问它。类似地,如果结构体的字段以大写开头,则可以从其他包访问它们。

示例代码:

  1. 在computer目录下,创建文件spec.go

    1
    2
    3
    4
    5
    6
    7
    package computer

    type Spec struct { //exported struct
    Maker string //exported field
    model string //unexported field
    Price int //exported field
    }
  2. 创建main.go文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package main

    import "computer"
    import "fmt"

    func main() {
    var spec computer.Spec
    spec.Maker = "apple"
    spec.Price = 50000
    fmt.Println("Spec:", spec)
    }

5 make new

  • make用于内建类型(map、slice 和channel)的内存分配。new用于各种类型的内存分配
  • 内建函数new本质上说跟其它语言中的同名函数功能一样:new(T)分配了零值填充的T类型的内存空间,并且返回其地址,即一个*T类型的值。用Go的术语说,它返回了一个指针,指向新分配的类型T的零值。有一点非常重要:new返回指针
  • 内建函数make(T, args)与new(T)有着不同的功能,make只能创建slice、map和channel,并且返回一个有初始值(非零)的T类型,而不是*T。本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个slice,是一个包含指向数据(内部array)的指针、长度和容量的三项描述符;在这些项目被初始化之前,slice为nil。对于slice、map和channel来说,make初始化了内部的数据结构,填充适当的值。
  • make返回初始化后的(非零)值。

6 参考

  1. Golang中国,https://www.qfgolang.com/