## 定義
Go語言可以通過自定義的方式形成新的類型,結構體就是這些類型中的一種復合類型,結構體是由零個或多個任意類型的值聚合成的實體,每個值都可以稱為結構體的成員。
結構體成員也可以稱為“字段”,這些字段有以下特性:
- 字段擁有自己的類型和值;
- 字段名必須唯一;
- 字段的類型也可以是結構體,甚至是字段所在結構體的類型。
使用關鍵字 type 可以將各種基本類型定義為自定義類型,基本類型包括整型、字符串、布爾等。結構體是一種復合的基本類型,通過 type 定義為自定義類型后,使結構體更便于使用。
```
type 類型名 struct{
字段 類型
}
```
例如:
```
type Person struct{
name string
age int
}
```
同類型的變量也可以寫在一行
```
type Person struct{
name, email string
age int
}
```
## 實例化
結構體的定義只是一種內存布局的描述,只有當結構體實例化時,才會真正地分配內存,因此必須在定義結構體并實例化后才能使用結構體的字段。
實例化就是根據結構體定義的格式創建一份與格式一致的內存區域,結構體實例與實例間的內存是完全獨立的。
Go語言可以通過多種方式實例化結構體,根據實際需要可以選用不同的寫法。
**var 實例化方式**
```
package main
import "fmt"
type Person struct{
name string
age int
}
func main() {
var tom = Person
tom.name = "Tom"
tom.age = 18
// var tom = Person{"Tom", 18} 可以省略字段名,但是順序必須一一對應
fmt.Println(tom) // {Tom 18}
}
```
**new 實例化方式**
```
package main
import "fmt"
type Person struct{
name string
age int
}
func main() {
tom := new(Person)
tom.name = "Tom"
tom.age = 18
fmt.Println(tom) // &{Tom 18}
}
```
## 結構體初始化
**使用“鍵值對”初始化結構體**
```
type Person struct{
name string
age int
}
user := Person{name: "Tony", age: 18}
```
**省略鍵初始化結構體**
```
type Person struct{
name string
age int
}
user := Person{"Tony", 18}
```
**初始化匿名結構體**
匿名結構體的初始化寫法由結構體定義和鍵值對初始化兩部分組成,結構體定義時沒有結構體類型名,只有字段和類型定義,鍵值對初始化部分由可選的多個鍵值對組成:
```
init := struct {
// 匿名結構體字段定義
字段 字段類型
…
}{
// 字段值初始化,注意每行結尾必須有逗號
初始化字段: 字段的值,
…
}
```
```
package main
import "fmt"
func main() {
init := struct{
name string
age int
}{
name: "Tom",
age: 18,
}
fmt.Printf("%v", init) // {Tom 18}
}
```
## 匿名字段
Go語言支持只提供類型,而不寫字段名的方式,也就是匿名字段,或稱為嵌入字段。
當匿名字段是一個struct的時候,那么這個struct所擁有的全部字段都被隱式地引入了當前定義的這個struct。
```
package main
import "fmt"
type Person struct{
name string
age int
}
type Tom struct{
Person
height int
}
func main() {
tom := Tom{Person{"Tom", 18}, 180}
fmt.Printf("%v", tom.name) // Tom
// 通過Person作為字段名訪問
fmt.Printf("%v", tom.Person.name) // Tom
}
```
自定義類型和內置類型等都可以作為匿名字段,而且還可以在相應的字段是進行函數操作:
```
package main
import "fmt"
type Person struct{
name string
age int
}
// 類型定義
type Skills []string
type Tom struct{
Person // 匿名字段,struct
Skills // 匿名字段,自定義類型 string slice
height int
int // 內置類型作為匿名字段
}
func main() {
tom := Tom{Person:Person{"Tom", 18}, Skills: []string{"computer", "excel"}, height: 180}
fmt.Printf("his name is:%s\n", tom.name) // he name is:Tom
// 修改 skill 字段
tom.Skills = append(tom.Skills, "Python")
fmt.Printf("his skills are:%v\n", tom.Skills) // he skills are:[computer excel Python]
// 修改匿名內置類型
tom.int = 50
fmt.Printf("%d", tom.int) // 50
}
```
如果 Person 里有個 phone 字段,而 Tom 里也有個 phone 字段,當通過 tom.phone 訪問,會優先訪問最外層的字段
這樣就允許我們去重載通過匿名字段繼承的一些字段,當然如果我們想訪問重載后對應匿名類型里面的字段,可以通過匿名字段名來訪問。
```
package main
import "fmt"
type Person struct{
name , phone string
age int
}
type Tom struct{
Person // 匿名字段,struct
phone string
}
func main() {
tom := Tom{Person:Person{"Tom", "xxx", 18}, phone: "xxxxxx"}
fmt.Printf("his phone is:%s\n", tom.phone) // his phone is:xxxxxx
fmt.Printf("his phone is:%s\n", tom.Person.phone) // his phone is:xxx
}
```