Go语言学习篇02

Go语言

Golang数组

数组应用实例

1)创建一个byte类型的26个元素的数组,分别 放置 ‘A’-‘z’。使用 for 循环访问所有元素并打印出来。

​ 提示:字符数据运算 ‘A’+1 -> ‘B’

思路

  1. 声明一个数组 var letterArr [26]byte
  2. 使用for循环来进行赋值
  3. 使用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个数,反转打印

注意

  1. 交换次数 len / 2
  2. 倒数第一个和第一个元素交换,倒数第二个和第二个交换…
  3. len(intArr)内建函数调用次数过多,资源浪费
  4. 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个学生的成绩:611个班级平均分=60.5
请输入2班第1个学生的成绩:63
请输入2班第2个学生的成绩:642个班级平均分=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

猜你喜欢

转载自blog.csdn.net/IT_Carter/article/details/110087400