[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
```
![](https://img.kancloud.cn/77/c4/77c487f6965db9beb1ed882be5805f76_880x530.png)
- 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