以下原则仅个人娱乐使用:
结构体原则
& 结构体数组固定原则:在数组中容纳的结构体的数目是有限的
& 结构体切片无限大原则:在切片中容纳的结构体的数目是无限的,可以利用 append 函数进行追加
& 结构体数组传递值原则:结构体数组作为函数参数将传递值
& 结构体切片传递地址原则:结构体切片作为函数参数将传递地址
& 结构体首地址指向原则:结构体的首地址指向结构体第一个成员
& 结构体传递值原则:结构体作为函数参数传递时是值传递
map 原则
& map 键值存在原则:利用语句 _, ok := 字典名[字典索引] 返回布尔值来检测
& map 没有也不抱怨原则:若 map 中并没有定义相关键值对,但是却进行了读操作,也不会报错,而是以值对应类型的默认值输出
& map 抛弃元素原则:利用 delete(字典名, key名) 来删除 map 中对应的元素
& map int 对应结构体属性直接写错误:创建 make(map[int]Student) 的 map,通过 m[1].score 直接修改属性是错误的
& map 传递地址原则:map 作为函数参数传递时是地址传递
结构体的声明和初始化
语法:type 结构体名 struct { 结构体成员列表 }
重点:以下程序提及了三种初始化结构体的方法
package main
import "fmt"
// 声明结构体类型 Student
type Student struct {
id int
name string
score int
}
func main() {
// 1. 顺序初始化
var stu_1 Student = Student{1, "Su shuo han", 100}
fmt.Println(stu_1) // {1 Su shuo han 100}
// 2. 自动推导和关键字赋值
stu_2 := Student{id: 2, name: "Xiao ke", score: 100}
fmt.Println(stu_2) // {2 Xiao ke 100}
// 3. 先声明后赋值
// 声明结构体
var stu_3 Student
// 初始化
stu_3.id = 3
stu_3.name = "Xiao jia"
stu_3.score = 100
fmt.Println(stu_3) // {3 Xiao jia 100}
}
第一种:按照顺序初始化结构体
var stu_1 Student = Student{1, "Su shuo han", 100}
第二种:按照关键词传参初始化结构体(自动推导)
stu_2 := Student{id: 2, name: "Xiao ke", score: 100}
第三种:先声明结构体然后赋值
var stu_3 Student
stu_3.id = 3
stu_3.name = "Xiao jia"
stu_3.score = 100
结构体名的含义 – 首地址
重点:结构体的首地址和结构体内首元素的地址相同(即结构体首地址指向原则);且取结构体的地址需要用到 & 符号(即结构体名指向第一个成员的地址)
package main
import "fmt"
// 声明结构体类型 Student
type Student struct {
id int
name string
score int
}
func main() {
// 初始化结构体
stu_1 := Student{1, "Su", 100}
// 打印结构体的首地址和结构体首个元素的地址
fmt.Printf("%p\n", &stu_1) // 0xc0000443c0
fmt.Printf("%p\n", &stu_1.id) // 0xc0000443c0
}
结构体联系数组和切片
以下程序用一个长度为 3 的数组来容纳 3 个结构体
package main
import "fmt"
// 声明结构体类型 Student
type Student struct {
id int
name string
score int
}
func main() {
// 初始化结构体数组
var arr_Student [3]Student = [3]Student{
{1, "Xiao su", 100},
{2, "Xiao ke", 100},
{3, "Liu jia", 100},
}
// 分别打印结构体数组中的元素
for i := 0; i < len(arr_Student); i++ {
fmt.Println("序号:", arr_Student[i].id, "名字:", arr_Student[i].name, "分数:", arr_Student[i].score)
}
// outputs:序号: 1 名字: Xiao su 分数: 100
// 序号: 2 名字: Xiao ke 分数: 100
// 序号: 3 名字: Liu jia 分数: 100
}
利用数组容纳结构体(即数组结构体固定原则),需要定义数组的长度,也就是说容纳结构体的数量有限
var arr_Student [3]Student // 3 个
以下程序用一个切片来容纳结构体
package main
import "fmt"
// 声明结构体类型 Student
type Student struct {
id int
name string
score int
}
func main() {
// 初始化结构体切片
var arr_Student []Student = []Student{
{1, "Xiao su", 100},
{2, "Xiao ke", 100},
{3, "Liu jia", 100},
}
// 打印结构体切片
fmt.Println(arr_Student) // [{1 Xiao su 100} {2 Xiao ke 100} {3 Liu jia 100}]
// 利用 append 函数追加数据(追加的是 Student 类型的结构体)
arr_Student = append(arr_Student, Student{4, "Xiao li", 100}, Student{5, "Xiao ze", 100})
// 打印结构体切片
fmt.Println(arr_Student) // [{1 Xiao su 100} {2 Xiao ke 100} {3 Liu jia 100} {4 Xiao li 100} {5 Xiao ze 100}]
}
利用切片容纳结构体(即切片结构体无限大原则),不需要提前声明结构体的数目(可以用 append 函数追加)
var arr_Student []Student
结构体作为函数参数
重点:值传递(即结构体传递值原则)
package main
import "fmt"
type Student struct {
id int
score int
}
func display(stu Student) {
stu.score = 200
fmt.Println(stu) // {1 200}
}
func main() {
stu_1 := Student{1, 100}
// 调用函数
display(stu_1)
fmt.Println(stu_1) // {1 100}
}
结构体数组和切片作为函数参数
结构体数组作为函数参数相当于传递值(即结构体数组传递值原则)
package main
import "fmt"
// 声明结构体类型 Student
type Student struct {
id int
name string
score int
}
// 冒泡排序
func bubbleSort(arr [3]Student) {
for i := 0; i < len(arr)-1; i++ {
for j := 0; j < len(arr)-1-i; j++ {
if arr[j].score > arr[j+1].score {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
fmt.Println(arr) // [{2 Xiao ke 78} {3 Liu jia 92} {1 Xiao su 100}]
}
func main() {
// 初始化结构体切片
var arr_Student [3]Student = [3]Student{
{1, "Xiao su", 100},
{2, "Xiao ke", 78},
{3, "Liu jia", 92},
}
// 调用排序函数 -- 根据 score 从小到大排序
bubbleSort(arr_Student) // 切片作为函数参数 -- 地址传递
// 在 main 函数中输入排序后的结果
fmt.Println(arr_Student) // [{1 Xiao su 100} {2 Xiao ke 78} {3 Liu jia 92}]
}
结构体切片作为函数参数相当于传递地址(即结构体切片传递值原则)
package main
import "fmt"
// 声明结构体类型 Student
type Student struct {
id int
name string
score int
}
// 冒泡排序
func bubbleSort(arr []Student) {
for i := 0; i < len(arr)-1; i++ {
for j := 0; j < len(arr)-1-i; j++ {
if arr[j].score > arr[j+1].score {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
}
func main() {
// 初始化结构体切片
var arr_Student []Student = []Student{
{1, "Xiao su", 100},
{2, "Xiao ke", 78},
{3, "Liu jia", 92},
}
// 调用排序函数 -- 根据 score 从小到大排序
bubbleSort(arr_Student) // 切片作为函数参数 -- 地址传递
// 在 main 函数中输入排序后的结果
fmt.Println(arr_Student) // [{2 Xiao ke 78} {3 Liu jia 92} {1 Xiao su 100}]
}
map 的声明和初始化
事先声明:map 相当于其它语言里的字典
语法:var 字典名 map[键类型]值类型
如下程序可以比较一下数组、切片及 map 声明的不同之处
package main
import "fmt"
func main() {
// 空数组
var arr_int [3]int
fmt.Println(arr_int) // [0 0 0]
// 空切片
var slice_int []int
fmt.Println(slice_int) // []
// 空 map
var m map[int]string
fmt.Println(m) // map[]
}
重点:空 map 和空切片不可以进行赋值和取值操作
package main
func main() {
var slice_int []int
// slice_int[0] = 0 // Error!
var m map[int]sting
// m[0] = "Xiao su" // Error!
}
第一处重点:map 属性 – 长度
package main
import "fmt"
func main() {
// 空 map
var m map[int]string
// 长度
fmt.Println(len(m)) // 0
}
第二处重点:map 的初始化
语法:字典名 := make(map[键类型]值类型)
重点:map 的数据无序;map 的长度自动扩容
package main
import "fmt"
func main() {
// 声明非空的 map 变量
m := make(map[int]string)
// 赋值
m[0] = "Xiao su"
fmt.Println(m) // map[0:Xiao su]
}
map 的键和值
自定义场景一:学生对应其三门课程成绩
package main
import "fmt"
func main() {
// 定义键为 string 类型 值为 [3]int 的数组的 map
m := make(map[string][3]int)
// 分别赋值
m["Xiao su"] = [3]int{100, 90, 100}
m["Xiao ke"] = [3]int{100, 100, 90}
m["Xiao lo"] = [3]int{90, 100, 100}
fmt.Println(m) // map[Xiao ke:[100 100 90] Xiao lo:[90 100 100] Xiao su:[100 90 100]]
}
自定义场景二:序号对应学生
package main
import "fmt"
func main() {
// 定义键为 string 类型 值为 [3]int 的数组的 map
m := make(map[int]string)
// 分别赋值
m[1] = "Xiao ke"
m[2] = "Xiao su"
m[3] = "Xiao lo"
fmt.Println(m) // map[1:Xiao ke 2:Xiao su 3:Xiao lo]
}
自定义场景三:序号对应学生的个人信息
package main
import "fmt"
type Student struct {
id int
name string
score int
}
func main() {
// 定义键为 string 类型 值为 [3]int 的数组的 map
m := make(map[int]Student)
// 分别赋值
m[1] = Student{1, "Xiao su", 100}
m[2] = Student{2, "Xiao ku", 100}
m[3] = Student{3, "Xiao ki", 100}
fmt.Println(m) // map[1:{1 Xiao su 100} 2:{2 Xiao ku 100} 3:{3 Xiao ki 100}]
// 需要注意的如下操作是不被予许的(即 map int 对应结构体属性直接写错误原则)
// m[1].score = 1000 // Error!
stu := m[1]
stu.score = 1000
m[1] = stu
fmt.Println(m) // map[1:{1 Xiao su 1000} 2:{2 Xiao ku 100} 3:{3 Xiao ki 100}]
}
自定义场景四:序号对应班级内部的学生信息
package main
import "fmt"
type Student struct {
id int
score int
}
func main() {
m := make(map[int][]Student)
// 代表 1 班 中的二个学生
// 一个学生 100 分 -- 另一个学生 90 分
m[1] = []Student{
{1, 100},
{2, 90},
}
// 现在我们增加第三个学生
m[1] = append(m[1], Student{3, 80})
fmt.Println(m) // map[1:[{1 100} {2 90} {3 80}]]
}
重点1:判断键值对是否存在(即 map 键值存在原则)
重点2:不存在某键值对将打印对应类型默认值(即 map 没有也不抱怨原则)
重点3:删除 map 中的元素(即 map 删除元素原则)
package main
import "fmt"
func main() {
m := make(map[int]string)
m[0] = "Xiao su"
fmt.Println(m) // map[0:Xiao su]
// 1. 查询键值对是否存在
_, ok := m[4]
fmt.Println(ok) // false
_, ok = m[0]
fmt.Println(ok) // true
// 2. 打印不存在的键值对
fmt.Println(m[5]) // 空字符
// 3. 删除键值对 -- 根据 key 值
delete(m, 0)
fmt.Println(m) // map[]
}
map 作为函数参数
重点:地址传递(即 map 传递地址原则)
package main
import "fmt"
func Change(m map[int]string) {
m[1] = "Xiao ke"
}
func main() {
m := make(map[int]string)
m[1] = "Xiao su"
fmt.Println(m) // map[1:Xiao su]
Change(m)
fmt.Println(m) // map[1:Xiao ke]
}