# 04.2 结构体

数组，切片，映射这类数据结构的确很有用，但是它们不能将多个值聚合到同一个地方。如果你想要将不同类型的不同变量聚合到一个地方以创建一个新的类型，那么结构体会满足你的需要。结构体中的不同元素叫做**结构体的字段**。

本章我们以一个简单的结构体为例来讲解，上一章的`sortSlie.go`中我们定义过一个结构体:

> ```go
> type aStructure struct {
>
>   person string
>
>   height int
>
>   weight int
> }
> ```

其实结构体的字段通常是大写字母开头，这个原因我们将在第六章中具体说明，这个习惯会贯穿本书接下来的内容。

这个结构体有三个字段，分别是`person,height,weight`。现在，你可以创建一个类型为`aStructure`的变量了:

> var s1 aStructure

另外，我们使用`.`操作符来访问结构体中的字段，例如我们可以使用`s1.person`来获取`person`字段的值。

一个**结构体字面量**可以这样定义：

> p1 := aStructure{"fmt",12,-2}

然而你可能觉得记住结构体中字段的声明顺序实在是太难了，莫慌，我们有另外一种定义结构体字面量的方式:

> p1 := aStructure{weight: 12, height:-2}

这种方式你无须初始化结构体中的所有字段。

现在你已经了解了结构体的基本操作，让我们尝试一些实战性更强的代码吧，这部分代码保存在`structures.go`中，分为三部分。

第一部分代码：

> ```go
> package main
>
> import "fmt"
>
> func main(){
>    type XYZ struct {
>       X int
>       Y int
>       Z int
>    }
>
>    var s1 XYZ
>    fmt.Println(s1.Y, s1.Z)
> ```

> Go结构体通常来说是定义在`main()`函数外面的，这样在整个Go package中可以拥有全局的属性，除非你不想让你的结构体在任何地方都被访问到，这种情况下你可以定义局部的结构体。

第二部分代码：

> ```go
> p1 := XYZ{23,12, -2}
> p2 := XYZ{Z:12,Y:13}
>
> fmt.Println(p1)
> fmt.Println(p2)
> ```

我们使用两种定义结构体字面量的方式定义了`p1`与`p2`,并且打印出来。

最后一部分：

> ```go
> pSlice := [4]XYZ{}
>    pSlice[2] = p1
>    pSlice[0] = p2
>
>    fmt.Println(pSlice)
>
>    p2 = XYZ{1,2,3}
>    fmt.Println(pSlice)
> }
> ```

最后一部分代码中，我们创建了一个结构体数组`pSlice`，当你将一个结构体分配给结构体数组，那么这个结构体就会被深拷贝至这个数组，这意味着改变原结构体是对数组中的结构体没有影响的，从下面的打印输出中我们能够看出来：

> $ go run structures.go
>
> 0 0 {23 12 -2} {0 13 12} \[{0 13 12} {0 0 0} {23 12 -2} {0 0 0}]
>
> \[{0 13 12} {0 0 0} {23 12 -2} {0 0 0}]

> 注意，结构体中字段的定义顺序是有意义的，简单来说，就算两个结构体拥有相同的字段，但是字段的声明顺序不同，那么这两个结构体也是不相等的。

从程序输出中我们能够知道，结构体中的变量是初始化为其类型的零值。
