[TOC]
結構體的定義只是一種內存布局的描述,只有當結構體實例化時,才會真正地分配內存。因此必須在定義結構體并實例化后才能使用結構體字段。實例化就是根據結構體定義的格式創建一份與格式一致的內存區域。結構體實例與實例間內存是完全獨立的。
## 實例化
有四種實例化結構體的方式,其中一種是匿名結構體。
```go
package main
import "fmt"
// Student 學生的結構體
type Student struct {
sid, age int
name string
course []string
}
func main() {
// (1)基本實例化
var s1 Student
fmt.Printf("s1: %#v\n", s1)
// (2)取結構體的地址實例化
s2 := &Student{}
fmt.Printf("s2: %#v\n", s2)
// 正常指針賦值操作如下
(*s2).age = 18
fmt.Printf("s2.age: %#v\n", (*s2).age)
// go語言為了方便開發者訪問結構體指針成員變量簡單, 使用了語法糖技術。
s2.name = "jiaxzeng"
fmt.Printf("s2.name: %#v\n", s2.name)
// (3)創建指針類型結構體
s3 := new(Student)
fmt.Printf("s3: %#v\n", s3)
// (4)匿名結構體
var user struct {
Name string
age int8
}
fmt.Printf("user: %#v\n", user)
}
// 運行結果
// s1: main.Student{sid:0, age:0, name:"", course:[]string(nil)}
// s2: &main.Student{sid:0, age:0, name:"", course:[]string(nil)}
// s3: &main.Student{sid:0, age:0, name:"", course:[]string(nil)}
// user: struct { Name string; age int8 }{Name:"", age:0}
```
> 在go語言中,結構體指針的變量可以繼續使用 `.` ,這是因為go語言為了方便開發者訪問結構體指針成員變量可以像訪問結構體的成員變量一樣簡單。使用了語法糖技術。將 instance.Name 形式轉換為 (*instance).Name 。
## 初始化
```go
package main
import "fmt"
// Student 學生的結構體
type Student struct {
sid, age int
name string
course []string
}
func main() {
// 列表初始化
// 按照順序依次賦值(所有值都需要賦值)
s4 := Student{1, 22, "jiaxzeng", []string{"Golang", "Python"}}
fmt.Printf("s4: %#v\n", s4)
s5 := &Student{sid: 2, age: 18, name: "xiaodunan"}
fmt.Printf("s5: %#v\n", s5)
// 鍵值對初始化
// 按照key名稱賦值(可以只賦值某些字段,其他字段使用類型默認值)
s6 := Student{sid: 3, name: "jiaxzeng"}
fmt.Printf("s6: %#v\n", s6)
s7 := &Student{4, 18, "xiaodunan", []string{"nginx", "mysql"}}
fmt.Printf("s7: %#v\n", s7)
}
// 運行結果
// s4: main.Student{sid:1, age:22, name:"jiaxzeng", course:[]string{"Golang", "Python"}}
// s5: &main.Student{sid:2, age:18, name:"xiaodunan", course:[]string(nil)}
// s6: main.Student{sid:3, age:0, name:"jiaxzeng", course:[]string(nil)}
// s7: &main.Student{sid:4, age:18, name:"xiaodunan", course:[]string{"nginx", "mysql"}}
```
>[info] 使用這種格式初始化時,需要注意:
> 1. 必須初始化結構體的所有字段。
> 2. 初始值的填充順序必須與字段在結構體中的聲明順序一致。
> 3. 該方式不能和鍵值初始化方式混用。
## 存儲原理
之前我們學習過值類型和引用類型,知道值類型是變量對應的地址直接存儲,而引用類型是變量對應地址存儲的地址。因為結構體因為是值類型,所以s的地址與存儲的第一個值的地址相同的,而后面每個成員變量的地址是連續的。
```go
type Student struct {
id int
name string
age int8
course []string
}
func main() {
var s = Student{1, "jiaxzeng", 18, []string{"Golang", "Python"}}
fmt.Printf("s is points: %p\n", &s)
fmt.Printf("s.id is points: %p\n", &s.id)
fmt.Printf("s.name is points: %p\n", &s.name)
fmt.Printf("s.age is points: %p\n", &s.age)
fmt.Printf("s.course is points: %p\n", &s.course)
}
// 運行結果
// s is points: 0xc0000b8040
// s.id is points: 0xc0000b8040
// s.name is points: 0xc0000b8048
// s.age is points: 0xc0000b8058
// s.course is points: 0xc0000b8060
```

- Golang簡介
- 開發環境
- Golang安裝
- 編輯器及快捷鍵
- vscode插件
- 第一個程序
- 基礎數據類型
- 變量及匿名變量
- 常量與iota
- 整型與浮點型
- 復數與布爾值
- 字符串
- 運算符
- 算術運算符
- 關系運算符
- 邏輯運算符
- 位運算符
- 賦值運算符
- 流程控制語句
- 獲取用戶輸入
- if分支語句
- for循環語句
- switch語句
- break_continue_goto語法
- 高階數據類型
- pointer指針
- array數組
- slice切片
- slice切片擴展
- map映射
- 函數
- 函數定義和調用
- 函數參數
- 函數返回值
- 作用域
- 函數形參傳遞
- 匿名函數
- 高階函數
- 閉包
- defer語句
- 內置函數
- fmt
- strconv
- strings
- time
- os
- io
- 文件操作
- 編碼
- 字符與字節
- 字符串
- 讀寫文件
- 結構體
- 類型別名和自定義類型
- 結構體聲明
- 結構體實例化
- 模擬構造函數
- 方法接收器
- 匿名字段
- 嵌套與繼承
- 序列化
- 接口
- 接口類型
- 值接收者和指針接收者
- 類型與接口對應關系
- 空接口
- 接口值
- 類型斷言
- 并發編程
- 基本概念
- goroutine
- channel
- select
- 并發安全
- 練習題
- 第三方庫
- Survey
- cobra