Go 语言结构体和 map

以下原则仅个人娱乐使用:

结构体原则

& 结构体数组固定原则:在数组中容纳的结构体的数目是有限的

& 结构体切片无限大原则:在切片中容纳的结构体的数目是无限的,可以利用 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]
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是我来晚了!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值