Go语言
Golang数组
数组应用实例
1)创建一个byte类型的26个元素的数组,分别 放置 ‘A’-‘z’。使用 for 循环访问所有元素并打印出来。
提示:字符数据运算 ‘A’+1 -> ‘B’
思路
- 声明一个数组 var letterArr [26]byte
- 使用for循环来进行赋值
- 使用for进行打印
//方式1
var letter byte = 'A'
var letterArr [26]byte
for i := 0; i < len(letterArr); i++ {
letterArr[i] = letter
letter++
}
fmt.Printf("%c\n",letterArr)
//方式2
var letterArr [26]byte
for i := 0; i < len(letterArr); i++ {
letterArr[i] = 'A' + byte(i)
}
for i := 0; i < len(letterArr); i++ {
fmt.Printf("%c ",letterArr[i])
}
2)求出一个数组的最大值,并得到对应的下标
var intArr = [...]int {
10, 3, 30, 100, 0, -99, 199}
var max int
var index int
//传统方式
for i := 0; i < len(intArr); i++ {
if intArr[i] > max {
max = intArr[i]
index = i
}
}
fmt.Println(max , index)
var intArr2 = [...]int {
100, 200, 200, 201, 0, -99, 299}
//for-range方式
for i, value := range intArr2 {
if value > max {
max = value
index = i
}
}
fmt.Println(max , index)
3)请求出一个数组的和和平均值,for - range
注意平均值问题
var sum int
var intArr2 = [...]int {
6, 6, 6, 6, 6, 7}
for _, value := range intArr2 {
sum += value
}
//如何让平均值保留小数
fmt.Println(sum, float64(sum) / float64(len(intArr2)))
4)随机生成5个数,反转打印
注意
- 交换次数 len / 2
- 倒数第一个和第一个元素交换,倒数第二个和第二个交换…
- len(intArr)内建函数调用次数过多,资源浪费
- length := len(intArr)
var intArr [5]int
//内建函数也会耗费资源
length := len(intArr)
rand.Seed(time.Now().UnixNano())
for i := 0; i < length; i++ {
intArr[i] = rand.Intn(100) + 1
}
fmt.Println("intArr交换前:", intArr)
//反转打印,交换次数 len / 2,倒数第一个和第一个元素交换,倒数第二个和第二个交换...
var temp int = 0//临时变量
for i := 0; i < length / 2; i++ {
temp = intArr[length - 1 -i]
intArr[length - 1 -i] = intArr[i]
intArr[i] = temp
}
fmt.Println("intArr交换后:", intArr)
Golang切片
为什么需要切片?
案例
我们需要用一个数组用于保存学生成绩,但是学生的个数不确定,请问怎么办?
解决方案:使用切片
切片:是可变长数组
切片的基本介绍
1)切片的英文 slice
2)切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递机制
3)切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度都是一样
4)切片的长度是可以变化的,因此切片是一个可以动态变化的数组
5)切片定义的基本语法
var 变量名 []类型
比如:var a []int
快速入门
var intArr = [...]int{
0, 1, 2, 3, 4}
//slice切片引用数组 开始位置:index = 1,结束位置:index = 3(但不包含3)
var slice []int = intArr[1:3]
for i := 0; i < len(slice); i++ {
slice[i] = 99
fmt.Println(slice[i])
}
fmt.Println("intArr的内容=", intArr)
fmt.Println("slice的元素=", slice)
fmt.Println("slice的元素个数=", len(slice))
fmt.Println("slice的容量=", cap(slice))//当前容量值,一般是个数的两倍,容量值可以变化
结果
99
99
intArr的内容= [0 99 99 3 4]
slice的元素= [99 99]
slice的元素个数= 2
slice的容量= 4
切片内存布局
切片使用的三种方法
- 方式1
- 第一种方式:定义一个切片,然后切片去引用一个已经创建好的数组
- 方式2
- 第二种方式:通过make来创建切片
- 基本语法:var 切片名 []type = make([], len, [cap])
- 参数说明:
- type就是数据类型
- len:大小
- cap:指定切片容量
- 方式3
- 第3种方式:定义一个切片,直接就指定具体数组,原理类似于make
//方式1
//通过引用数组来进行,数组实现存在,可见
var intArr = [...]int{
0, 1, 2, 3, 4}
//slice切片引用数组 开始位置:index = 1,结束位置:index = 3(但不包含3)
var slice []int = intArr[1:3]
//方式2
//make内置函数,make创建数组,不可见
var slice []int = make([]int, 4, 10)
slice[0] = 100
slice[1] = 200
slice[2] = 300
slice[3] = 400
fmt.Println(slice)
//方式3
//定义指定数组
var slice []string = []string{
"carter", "tom"}
fmt.Println(slice)
fmt.Println(len(slice))
fmt.Println(cap(slice))
内存分配
切片面试题
1)方式1是直接引用数组,数组事先存在,程序员可见
2)方式2是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是看不见的
切片的遍历
切片的遍历和数组一样有两种方式
1)for循环遍历
2)for-range切片遍历
var arr [5]int = [5]int{
10, 20, 30, 40,50}
var slice []int = arr[1:5]
//common for loop traversal
for i := 0; i < len(slice); i++ {
fmt.Printf("slice[%v]=%v\n", i, slice[i])
}
// for - range
for index, value := range slice {
fmt.Printf("index=%v,value=%v\n", index, value)
}
切片注意事项和细节说明
1)切片初始化时 var slice = arr [startIndex : endIndex]
说明:从arr数组下标为startIndex,取到下标为endIdex(不含 arr[endIndex])
2)切片初始化,不能越界。范围在[0 - len(arr)] 之间, 但是可以动态增长。
- var slice = arr[0 : end] 可以简写:var slice = arr[ : end]
- var slice = arr[start : len(arr)] 可以简写:var slice = arr[start : ]
- var slice = arr[0 : len(arr)] 可以简写:var slice = arr[ : ]
3)cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素
4)切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用【声明】
5)定义不能使用,声明后才能使用
6)切片还可以切片
slice02 = slice01[1:2]
切片内置函数append
func append
func append(slice []Type, elems ...Type) []Type
内建函数append将元素追加到切片的末尾。若它有足够的容量,其目标就会重新切片以容纳新的元素。否则,就会分配一个新的基本数组。append返回更新后的切片,因此必须存储追加后的结果。
var arr [5]int = [5]int{
10, 20, 30, 40, 50}
var slice []int = arr[1:5]
slice01 := slice [2:]
//Way 1 additional concrete elements
slice01 = append(slice01, 999, 999, 999)
//Way 2 additional slice
slice01 = append(slice01, slice01...)
fmt.Println(slice01)
切片操作的底层原理分析
1)切片append操作的本质就是对数组的扩容
2)go底层会创建一个新的数组newArr(安装扩容后大小)
3)将slice原来包含的元素拷贝到新的数组newArr
4)slice重新引用到newArr
5)注意newArr是在底层来维护的,程序员不可见
切片append底层原理分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8WRmsUbe-1606208577830)(Go语言学习篇02.assets/
)]
最终模型
- 没有引用的数组会被垃圾回收机制回收
切片的copy操作
1)都是切片类型才行
2)数据空间独立,相互不影响
var slice01 []int = []int{
10, 20, 30, 40, 50}
var slice02 = make([]int,10)
copy(slice02, slice01)
fmt.Println(slice01)
fmt.Println(slice02)
结果
[10 20 30 40 50]
[10 20 30 40 50 0 0 0 0 0]
长度不够copy仍有效
var a []int = []int{
1,2,3,4,5}//长度是5
var slice = make([]int, 1)//长度是1
fmt.Println(slice)
copy(slice, a)//将长度是5 copy 给长度是1的 并不会报错
fmt.Println(slice)
结果
[0]
[1]
string 与切片
1)string的底层是一个byte数组,因此string也可以进行切片处理
2)string是不可变的,str[0]='Z’是行不通的
3)字符串修改,将字符串变成切片,修改后返回字符
相当于substring
str := "hello@world"
//@后面一位开始
startIndex := strings.Index(str,"@")+1
fmt.Println(startIndex)
slice := str[startIndex:]
fmt.Println(slice)
结果
6
world
string内存图
string的复杂改变
//字符串
str := "hello@world"
//找出字符串中位置
index := strings.Index(str, "@")
//1、byte切片化
byteArr := []byte(str)
//将@变成空格
byteArr[index] = ' '
//2、string化
str = string(byteArr)
fmt.Println(str)
结果
hello world
思考题:如果不是@符号,而是是中文该何如???
解决方案:使用[]rune
,因为rune按字符
处理
代码
str := "hello@world"//定义声明一个字符串
index := strings.Index(str, "@")//找出字符串中位置
byteArr := []rune(str)//1、rune切片化
byteArr[index] = '中'//2、将@ 变成 '中'
str = string(byteArr)//3、string化
fmt.Println(str)//输出
结果
hello中world
切片课堂练习
说明:编写一个函数fbn(n int),要求完成
1)可以接收一个 n int
2)能够将斐波那契数列放入切片中
3)提示,斐波那契数列的数列形式:
arr[0] = 1; arr [1] = 1; arr[2] = 2; arr[3] = 3; arr[4] = 5; arr[5] = 8 …
思路
1)声明一个函数
2)定义声明一个切片
3)for循环存放斐波那契数
代码
func fbn(n int) []uint64 {
//定义声明一个切片
var fbnSlice []uint64 = make([]uint64, n)
//第一个数和第二个数的斐波那契数是 1
fbnSlice[0] = 1
fbnSlice[1] = 1
//其它的for循环
for i := 2; i < n; i++ {
fbnSlice[i] = fbnSlice[i - 1] + fbnSlice[i - 2]
}
return fbnSlice
}
func main() {
slice := fbn(6)
fmt.Println(slice)
}
结果
[1 1 2 3 5 8]
Golang数组排序+查找
排序基本介绍
排序是将一组数据,依照指定的顺序进行排序的过程
排序的分类:
1)內部排序(一次性)
指将需要处理的所有数据都加载到内部存储中进行排序(数据量比较小)
包括(交换式排序法
、选择排序法
和插入排序法
)
2)外部排序(一部分一部分加载)
数据量过大,无法全部加载到内存中,需要借助外部存储进行排序
包括(合并排序法
、直接合并排序法
)。
-
内部排序
-
交换排序
-
1、冒泡排序 (Bubble Sorting)
-
2、快速排序(Quick Sorting)
-
-
冒泡排序法
案例
24,69, 64,100,21 无序数组,进行从小到大的冒泡排序
由内而外的书写
代码
//指针运算更快
func bubbleSort(intArr *[5]int){
fmt.Println("intArr交换前:", *intArr)
length := len(*intArr)
var temp int = 0
for i := 0; i < length - 1; i++ {
for j := 0; j < length - i -1; j++ {
if (*intArr)[j] > (*intArr)[j+1] {
temp = (*intArr)[j]
(*intArr)[j] = (*intArr)[j+1]
(*intArr)[j+1] = temp
}
}
}
}
func main() {
var intArr [5]int = [5]int{
28, 67, 13, 11, 7}
bubbleSort(&intArr)
fmt.Println("intArr交换后:", intArr)
}
结果
intArr交换前: [28 67 13 11 7]
intArr交换后: [7 11 13 28 67]
顺序查找
案例
1)有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王
猜数游戏:从键盘任意输入一个名称,判断数列中是否含有此名称【顺序查找】
var nameArr [4]string = [4]string{
"黑山老妖", "太乙真人", "紫霞仙子", "菩提老祖"}
var heroName string = ""
var length int = len(nameArr)
fmt.Println("请输入你要查找的仙人:")
fmt.Scanln(&heroName)
//第1种方式:顺序查找
for i := 0; i < length; i++ {
if heroName == nameArr[i] {
fmt.Printf("恭喜你,天选之子找到了%v,下标%v\n", heroName, i)
break
} else if i == length - 1 {
fmt.Println("I am so sorry, You can not find", heroName)
}
}
//第2种方式--->一般用这种方法
index := -1
for i := 0; i < length; i++ {
if heroName == nameArr[i] {
index = i
break
}
}
if index != -1 {
fmt.Printf("恭喜你,天选之子找到了%v,下标%v\n", heroName, index)
} else {
fmt.Println("I am so sorry, You can not find", heroName)
}
二分查找
2)对一个有序数组进行二分查找 {1, 8, 10, 89, 100, 123},输入一个数看看该数组是否存在此数,并且求出下标,如果没有 提示“没有这个数”【会使用到递归】
思路分析
分析
1)两个指针,在最两端
2)值比较 (startIndex + endIndex) / 2
3)两端指针变动
代码
package main
import (
"fmt"
)
var (
count int
slice01 []int
slice02 []int
)
func BinaryFind(arr *[6]int, leftIndex int,rightIndex int, findVal int) {
if leftIndex > rightIndex {
fmt.Println("TMD,没有找到...")
return
}
//中间下标
middle := (leftIndex + rightIndex) / 2
slice01 = append(slice01, middle)
slice02 = append(slice02, (*arr)[middle])
count++
if (*arr)[middle] > findVal {
//在左边
BinaryFind(arr, leftIndex, middle - 1, findVal)
} else if (*arr)[middle] < findVal {
//在右边
BinaryFind(arr, middle + 1, rightIndex, findVal)
} else {
//找到了
fmt.Printf("恭喜你,在index=%v 找到了%v\n", middle, (*arr)[middle])
}
}
func main() {
var intArr [6]int = [6]int{
1, 8, 10, 89, 100, 123}
BinaryFind(&intArr, 0, len(intArr) - 1, -8)
fmt.Printf("查找了%v次\n", count)
fmt.Println("依次经过的下标:", slice01)
fmt.Println("依次经过的值:", slice02)
}
结果
TMD,没有找到...
查找了2次
依次经过的下标: [2 0]
依次经过的值: [10 1]
Goalng 二维数组
快速入门案例
1)利用二维数组打印出
0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 0 3 0
0 0 0 0 0 0
代码
var intArray [4][6]int
intArray[1][2] = 1
intArray[2][1] = 2
intArray[2][4] = 3
//for _, value := range intArray {
// for _, value := range value {
// fmt.Printf("%v ", value)
// }
// fmt.Println()
//}
for i := 0; i < len(intArray); i++ {
for j := 0; j < len(intArray[i]); j++ {
fmt.Print( " ", intArray[i][j])
}
fmt.Println()
}
二维数组在内存中的布局
二维数组应用案例
定义二维数组,用于保存三个班,每个班5名同学的成绩,
并求出每个班级的平均分,以及所有班级的平均分!
思路
1)二维数组 3个元素,每个元素下含5个元素
2)控制台输入学生成绩
3)求出班平均成绩
4)所有班的平均成绩
代码
func main() {
var intArr [2][2]float64
var classAverageScore float64 = 0.0
for i := 0; i < len(intArr); i++ {
//班级平均成绩
var averageScore float64 = 0.0
for j := 0; j < len(intArr[i]); j++ {
fmt.Printf("请输入%v班第%v个学生的成绩:", i+1, j+1)
fmt.Scanln(&intArr[i][j])
averageScore += intArr[i][j]
}
fmt.Printf("第%v个班级平均分=%v\n",i+1 ,averageScore / float64(len(intArr[i])))
classAverageScore += averageScore
}
fmt.Printf("所有班级的平均分=%v\n" ,classAverageScore / float64(len(intArr) * len(intArr[0])))
}
结果
请输入1班第1个学生的成绩:60
请输入1班第2个学生的成绩:61
第1个班级平均分=60.5
请输入2班第1个学生的成绩:63
请输入2班第2个学生的成绩:64
第2个班级平均分=63.5
所有班级的平均分=62
Golang 核心编程map
map的介绍
map 是key-value 数据结构,又称为字段或者关联数组。类似其它编程语言的集合
map的声明
- 基本语法
var map变量名 map[keytype]valuetype
- key可以是什么类型?
- bool,数字,string,指针,channel,还可以只包含前面几个类型的 接口,结构体,数组
- 通常为int、string
注意: slice、map、function不可以做key,因为无法用 == 来判断
- value可以是什么类型?
- 与key基本一致
- 通常为:数字(整数、浮点数),string,map,struct
注意:声明是不分配内存的,初始化需要make,分配内存后才能进行赋值和使用
代码
//map的声明
var stringMap map[string]string
//在使用map之前需要先make,make的作用就是给map分配内存
stringMap = make(map[string]string, 2)
//Assignment
stringMap["name01"] = "宋江"
stringMap["name02"] = "武松"
stringMap["name03"] = "龙神"
stringMap["name04"] = "卡卡罗特"
stringMap["name05"] = "贝吉塔"
//后面的key值覆盖前面相同的key的值
stringMap["name05"] = "比鲁斯大人"
fmt.Println(stringMap)
结果
map[name01:宋江 name02:武松 name03:龙神 name04:卡卡罗特 name05:比鲁斯大人]
分析
1)map 在使用前一定要 make
2)map 的 key 不能重复,如果重复了,则以最后这个 key - value 为准
3)map 的 value 可以相同
4)map 的 key - value 是无序的
5)make 内置函数不定义size,默认size = 1
map 的3种使用方式
代码
//方式1
var stringMap01 map[string]string
stringMap01 = make(map[string]string)
stringMap01["name"] = "Carter"
stringMap01["sex"] = "男"
stringMap01["age"] = "20"
fmt.Println(stringMap01)
//方式2---推荐使用
var stringMap02 map[string]string = make(map[string]string)
stringMap02["name"] = "廖述幸"
stringMap02["sex"] = "男"
stringMap02["age"] = "20"
fmt.Println(stringMap02)
//方式3
var stringMap03 map[string]string = map[string]string{
"name" : "lsx",
"sex" : "man",
"age" : "18",
}
fmt.Println(stringMap03)
结果
map[age:20 name:Carter sex:男]
map[age:20 name:廖述幸 sex:男]
map[age:18 name:lsx sex:man]
map案例练习
我们要存放3个学生信息,每个学生有name和sex信息
思路
1)map[string]map[string]string
代码
var string2Map map[string]map[string]string = make(map[string]map[string]string)
//注意:内部的map使用前的make
string2Map["学生01"] = make(map[string]string)
string2Map["学生01"]["name"] = "胡歌"
string2Map["学生01"]["sex"] = "男"
//子map
fmt.Println(string2Map["学生01"])
string2Map["学生02"] = make(map[string]string)
string2Map["学生02"]["name"] = "范彬彬"
string2Map["学生02"]["sex"] = "女"
fmt.Println(string2Map["学生02"])
string2Map["学生03"] = make(map[string]string)
string2Map["学生03"]["name"] = "杨幂"
string2Map["学生03"]["sex"] = "女"
fmt.Println(string2Map["学生03"])
fmt.Println()
//父map
fmt.Println(string2Map)
结果
map[name:胡歌 sex:男]
map[name:范彬彬 sex:女]
map[name:杨幂 sex:女]
map[学生01:map[name:胡歌 sex:男] 学生02:map[name:范彬彬 sex:女] 学生03:map[name:杨幂 sex:女]]
map的增加和修改
map[key] = value
key
存在就是update
,不存在 就是 add
map的删除
delete函数
delete(stringMap, "key")//存在即删除
如何清空 map ?
1)Golang中只能遍历key 进行逐个删除
2)或者 map = make(…), make一个新的空间,让原来的成为垃圾,被GC回收
map的查找
value := stringMap["key"]
map增删改查总结
代码
var stringMap01 map[string]string = make(map[string]string)
//1、增加
stringMap01["carter"] = "廖述幸"
stringMap01["lsx"] = "廖述幸"
stringMap01["ct"] = "陈涛"
stringMap01["trz"] = "唐润1"
fmt.Println("修改前:", stringMap01)
//2、修改
stringMap01["trz"] = "唐润之"
fmt.Println("修改后:", stringMap01)
//3、删除操作 key存在就删除,不存在,不进行操作
delete(stringMap01, "童鞋")
fmt.Println("删除后:", stringMap01)
//3.1 清空map
//stringMap01 = make(map[string]string)
fmt.Println("清空后:", stringMap01)
//4、查询
value := stringMap01["carter"]
fmt.Println("carter--->", value)
输出
修改前: map[carter:廖述幸 ct:陈涛 lsx:廖述幸 trz:唐润1]
修改后: map[carter:廖述幸 ct:陈涛 lsx:廖述幸 trz:唐润之]
删除后: map[carter:廖述幸 ct:陈涛 lsx:廖述幸 trz:唐润之]
清空后: map[carter:廖述幸 ct:陈涛 lsx:廖述幸 trz:唐润之]
carter---> 廖述幸
map的遍历
1)map的 key 不一定是数字,得用for…range遍历
2)长度用len
for - range
var stringMap01 map[string]string = make(map[string]string)
stringMap01["1"] = "n1"
stringMap01["2"] = "n2"
stringMap01["3"] = "n3"
//for.. range traversal 简单点
for key, value := range stringMap01 {
fmt.Printf("key=%v value=%v\n", key, value)
}
//双重map 复杂的
var stringMap02 map[string]map[string]string = make(map[string]map[string]string)
stringMap02["1"] = make(map[string]string)
stringMap02["1"]["start"] = "thank"
stringMap02["1"]["end"] = "you"
stringMap02["2"] = make(map[string]string)
stringMap02["2"]["start"] = "hello"
stringMap02["2"]["end"] = "world"
stringMap02["3"] = make(map[string]string)
stringMap02["3"]["start"] = "yes"
stringMap02["3"]["end"] = "no"
fmt.Println()
for key1, value1 := range stringMap02 {
fmt.Println("key1=", key1)
for key2, value2 := range value1 {
fmt.Printf("\t key2=%v value2=%v\n", key2, value2)
}
fmt.Println()
}
结果
key=3 value=n3
key=1 value=n1
key=2 value=n2
key1= 1
key2=end value2=you
key2=start value2=thank
key1= 2
key2=start value2=hello
key2=end value2=world
key1= 3
key2=start value2=yes
key2=end value2=no
map切片(动态增加)
基本介绍:
切片的数据类型如果是map,则我们称为slice of map,map的切片
这样使用map的个数就可以动态变化
注意
1)切片动态增长,用append
代码
//Slice of map
//切片本身要make
//切片里面的map需要make
var monsters []map[string]string = make([]map[string]string, 2)
//add monster
if monsters[0] == nil {
monsters[0] = make(map[string]string)
monsters[0]["name"] = "蜘蛛精"
monsters[0]["age"] = "600"
}
if monsters[1] == nil {
monsters[1] = make(map[string]string)
monsters[1]["name"] = "红孩儿"
monsters[1]["age"] = "300"
}
//index out of range [2] with length 2 数组越界
//if monsters[2] == nil {
// monsters[2] = make(map[string]string)
// monsters[2]["name"] = "神奇女侠"
// monsters[2]["age"] = "27"
//}
//我们需要使用 append动态增加
//1.创建一个monster信息
newMonster := map[string]string{
"name" : "火云邪神",
"age" : "67",
}
//动态增加
monsters = append(monsters, newMonster)
fmt.Println(monsters[0])
fmt.Println(monsters[1])
fmt.Println(monsters[2])
结果
map[age:600 name:蜘蛛精]
map[age:300 name:红孩儿]
map[age:67 name:火云邪神]
map排序
基本介绍:
1)Golang中没有一个专门的方法针对map的key进行排序
2)Golang中的map默认是unordered
,遍历也是无序的
3)Golang中map排序,是先将key进行排序,然后根据 key 遍历输出即可
代码
import (
"fmt"
"sort"
)
func main() {
intMap := make(map[int]int)
intMap[0] = 1
intMap[2] = 2
intMap[1] = 3
fmt.Println(intMap)
//按照map的key的顺序输出
//1、将map的key放入slice中
//2、对切片排序
//3、遍历切片,按key输出value
var keySlices []int
for key, _ := range intMap {
keySlices = append(keySlices, key)
}
//排序包sort---升序
sort.Ints(keySlices)
fmt.Println("keySlices=", keySlices)
//遍历输出
for _, key := range keySlices {
fmt.Printf("intMap[%v]=%v\n",key, intMap[key])
}
}
结果
map[0:1 1:3 2:2]
keySlices= [0 1 2]
intMap[0]=1
intMap[1]=3
intMap[2]=2
struct做value
1)map是一个引用类型的,可通过函数接收map,进行修改
2)map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态增加(key - value)
3)map的value通常也是结构体struct
代码
package main
import (
"fmt"
"sort"
)
//1、定义一个学生的结构体
type student struct {
name string
age byte
address string
}
func main() {
//map的value 也经常使用struct类型
//更加适合管理复杂的数据(比用map更加好)
var structMap map[string]student = make(map[string]student)
//创建两个学生
//方式1
stu1 := student{
name: "carter", age: 18, address: "湖南"}
//方式2
stu2 := student{
"Mary", 18, "上海"}
//2、赋值到map
structMap["No1"] = stu1
structMap["No2"] = stu2
//3、声明切片 对key排序
var stringSlice []string
for key, _ := range structMap {
stringSlice = append(stringSlice, key)
}
//4、排序
sort.Strings(stringSlice)
//5、遍历
for _, key := range stringSlice {
fmt.Println("学生的编号:", key)
fmt.Println("学生的姓名:", structMap[key].name)
fmt.Println("学生的年龄:", structMap[key].age)
fmt.Println("学生的地址:", structMap[key].address)
fmt.Println()
}
//遍历打印---无序
//for key, value := range structMap {
// fmt.Println("学生的编号:", key)
// fmt.Println("学生的姓名:", value.name)
// fmt.Println("学生的年龄:", value.age)
// fmt.Println("学生的地址:", value.address)
// fmt.Println()
//}
}
结果
学生的编号: No1
学生的姓名: carter
学生的年龄: 18
学生的地址: 湖南
学生的编号: No2
学生的姓名: Mary
学生的年龄: 18
学生的地址: 上海
map课堂练习
1)使用 map[string]map[string]string 的map类型
2)key表示用户名,是唯一的,不可以重复
3)如果某个用户名存在,就将其密码修改“8888”,如果不存在就增加这个用户信息,包括(昵称nickName 和 password密码)
4)编写一个函数modifyUser(users map[string]map[string]string, name string)完成上述功能
代码
package main
import "fmt"
//全局变量
var (
stringMap map[string]map[string]string
nickName string = "nickName"
password string = "password"
)
func modifyUser(users map[string]map[string]string, username string) {
//查找用户
insideMap := users[username]
if insideMap != nil {
//用户存在:则修改密码
insideMap[password] = "8888"
} else {
//用户不存在:则添加用户
users[username] = make(map[string]string)
users[username][nickName] = "小"+username
users[username][password] = password
}
}
func forRange() {
for key, value := range stringMap {
fmt.Printf("\t昵称:%v\n", value[nickName])
fmt.Printf("\t用户名:%v\n", key)
fmt.Printf("\t密码:%v\n", value[password])
fmt.Println()
}
}
func main() {
//1、定义map
stringMap = make(map[string]map[string]string)
stringMap["username"] = make(map[string]string)
stringMap["username"][nickName] = "小样"
stringMap["username"][password] = password
//2、遍历map
fmt.Println("修改前")
forRange()
//3、调用函数modifyUser
var username string = "卡特"
modifyUser(stringMap, username)
//4、遍历map
fmt.Println("修改后")
forRange()
}
结果
修改前
昵称:小样
用户名:username
密码:password
修改后
昵称:小卡特
用户名:卡特
密码:password
昵称:小样
用户名:username
密码:password
码修改“8888”,如果不存在就增加这个用户信息,包括(昵称nickName 和 password密码)
4)编写一个函数modifyUser(users map[string]map[string]string, name string)完成上述功能
代码
package main
import "fmt"
//全局变量
var (
stringMap map[string]map[string]string
nickName string = "nickName"
password string = "password"
)
func modifyUser(users map[string]map[string]string, username string) {
//查找用户
insideMap := users[username]
if insideMap != nil {
//用户存在:则修改密码
insideMap[password] = "8888"
} else {
//用户不存在:则添加用户
users[username] = make(map[string]string)
users[username][nickName] = "小"+username
users[username][password] = password
}
}
func forRange() {
for key, value := range stringMap {
fmt.Printf("\t昵称:%v\n", value[nickName])
fmt.Printf("\t用户名:%v\n", key)
fmt.Printf("\t密码:%v\n", value[password])
fmt.Println()
}
}
func main() {
//1、定义map
stringMap = make(map[string]map[string]string)
stringMap["username"] = make(map[string]string)
stringMap["username"][nickName] = "小样"
stringMap["username"][password] = password
//2、遍历map
fmt.Println("修改前")
forRange()
//3、调用函数modifyUser
var username string = "卡特"
modifyUser(stringMap, username)
//4、遍历map
fmt.Println("修改后")
forRange()
}
结果
修改前
昵称:小样
用户名:username
密码:password
修改后
昵称:小卡特
用户名:卡特
密码:password
昵称:小样
用户名:username
密码:password