数组

数组可以存放多个同一类型数据。数组也是一种数据类型,在Go中,数组是值类型

一个养鸡场有6只鸡,它们的体重分别是3kg,5kg,1kg,3.4kg,2kg,50kg。请问这六只鸡的总体重是多少?平均体重是多少?

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
使用传统的方法不利于数据的管理和维护
传统的方法不够灵活,因此我们引出需要学习的新的数据类型  ==》数组

//使用数组的方式来解决问题
var 数组名 [数组大小]数据类型
var a [5]int
赋初值 a[0] = 1 a[1] = 30 ...
func main()  {
   //1.定义一个数组
   var hens [7]float64
   //2. 给数组的每个元素赋值,元素的下标是从0开始的 0 - 6
   hens[0] = 3.0  //hens数组的第1个元素 hens[0]
   hens[1] = 5.0  //hens数组的第2个元素 hens[1]
   hens[2] = 1.0
   hens[3] = 3.4
   hens[4] = 2.0
   hens[5] = 50.0
   hens[6] = 150.0 //增加一只鸡
   //3. 遍历数组求出总体重
   totalWeight := 0.0
   for i := 0; i < len(hens); i++ {
      totalWeight += hens[i]
   }
   //4. 求出平均体重
   avgWeight := fmt.Sprintf("%.2f",totalWeight / float64(len(hens)))
   fmt.Printf("totalWeight = %v avgWeight = %v",totalWeight,avgWeight)
}
//输出:totalWeight = 214.4 avgWeight = 30.63
使用数组来解决问题,增加程序的可维护性
而且方法代码更加清晰,也容易扩展

数组在内存布局 go语言系列-从数组到map go 第1张

数组的地址可以通过数组名来获取 &intArr
数组的第一个元素的地址,就是数组的首地址
数组的各个元素的地址间隔是依据数组的类型决定,比如 int64 -> 8    int32 -> 4 ...
func main()  {
   var intArr [3]int  //int占8个字节
   //当我们定义完数组后,其是数组的各个元素有默认值 0
   fmt.Println(intArr) // 默认值
   intArr[0] = 10
   intArr[1] = 20
   intArr[2] = 30
   fmt.Println(intArr)
   fmt.Printf("intArr的地址 = %p intArr[0] 地址 = %p intArr[1] 地址 = %p intArr[2] 地址 = %p",
      &intArr,&intArr[0],&intArr[1],&intArr[2])
}
//输出:[0 0 0]
//[10 20 30]
//intArr的地址 = 0xc000010380 intArr[0] 地址 = 0xc000010380 intArr[1] 地址 = 0xc000010388 intArr[2] 地址 = 0xc000010390

数组的使用

func main()  {
   var score [5]float64
   for i := 0; i < len(score); i++ {
      fmt.Printf("请输入第%d个元素的值\n",i+1)
      fmt.Scanln(&score[i])
   }
   //变量数组打印
   for i := 0; i < len(score); i++ {
      fmt.Printf("score[%d] = %v\t",i,score[i])
     //访问数组元素:数组名[下标]比如:要使用a数组的第三个元素 a[2]
   }
}

初始化数组的方式

func main() {
   //四种初始化数组的方式
   var numArr01 [3]int = [3]int{1,2,3}
   fmt.Println("numArr01 = ",numArr01)

   var numArr02  = [3]int{4,5,6}
   fmt.Println("numArr02 = ",numArr02)

   //这里的 [...]是规定的写法
   var numArr03 = [...]int{7,8,9}
   fmt.Println("numArr03 = ",numArr03)

   var numArr04 = [...]int{1: 800, 0: 900, 2: 999}
   fmt.Println("numArr04 = ",numArr04)

   //类型推导
   strArr05 := [...]string{1: "zisefeizhu", 0: "jack", 2: "mary"}
   fmt.Println("strArr05 = ",strArr05)
}
//输出:numArr01 =  [1 2 3]
//numArr02 =  [4 5 6]
//numArr03 =  [7 8 9]
//numArr04 =  [900 800 999]
//strArr05 =  [jack zisefeizhu mary]

数组的遍历

方法1:  常规遍历
遍历数组求出总体重
   totalWeight := 0.0
   for i := 0; i < len(hens); i++ {
      totalWeight += hens[i]
   }

方法2:for - range 结构遍历
第一个返回值index是数组的下标
第二个value是在该下标位置的值
它们都是仅在for循环内部可见的局部变量
遍历数组元素的时候,如果不想使用下标index,可以直接把下边index标为下划线_
index和value的名称不是固定的,即程序员可以自行指定,一般命名为index和value
 //演示for-range遍历数组
   heroes := [...]string{"宋江","吴用","林冲"}
   for i, v := range heroes {
      fmt.Printf("i = %v v = %v\n",i, v)
      fmt.Printf("heroes[%d] = %v \n",i,heroes[i])
   }
   for _,v := range heroes {
      fmt.Printf("元素的值 = %v\n",v)
   }
}
//输出:i = 0 v = 宋江
//heroes[0] = 宋江 
//i = 1 v = 吴用
//heroes[1] = 吴用 
//i = 2 v = 林冲
//heroes[2] = 林冲 
//元素的值 = 宋江
//元素的值 = 吴用
//元素的值 = 林冲

数组使用的注意事项和细节

数组是多个相同类型数组的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化
var arr []int 这时 arr就是一个slice切片,切片后面专门讲解
数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混合
数组创建后,如果没有赋值,有默认值(零值)
	数值类型数组:默认值为0
	字符串数组:  默认值为" "
	bool数组:   默认值为false
使用数组的步骤 
	1.声明数组并开辟空间
	2.给数组各个元素赋值(默认零值)
	3.使用数组
数组的下标是从0开始的
数组下标必须在指定范围内使用,否则报panic:数组越界,比如
	var arr[5]int 则有效下标为 0 - 4
Go的数组属于值类型,在默认情况下是值类型,因此会进行值拷贝。数组间不会相互影响

go语言系列-从数组到map go 第2张

如果想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)

go语言系列-从数组到map go 第3张

长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度

go语言系列-从数组到map go 第4张

数组的应用案例

创建一个byte类型的26个元素的数组,分别放置’A’ - ’Z’。使用for循环访问所有元素并打印出来。提示:字符数据运算’A’+1 →’B’

func main(){
   //1)创建一个byte类型的26个元素的数组,分别放置’A’ - ’Z’。
   // 使用for循环访问所有元素并打印出来。
   // 提示:字符数据运算’A’+1 ->’B’

   //思路
   //1. 声明一个数组 var myChars [26]byte
   //2. 使用for循环,利用 字符可以进行运算的特点来辅助 'A' + 1 = 'B'
   //3. 使用for 循环打印
   var myChars [26]byte
   for i := 0; i < 26; i++ {
      myChars[i] = 'A' + byte(i) //注意需要将i =》 byte
   }
   for i := 0; i < 26; i++ {
      fmt.Printf("%c",myChars[i])
   }
//输出:ABCDEFGHIJKLMNOPQRSTUVWXYZ
}

请求出一个数组的最大值,并得到对应的下标

func main() {
   //思路
   //1. 声明一个数组 var intArr[5] = [...]int{1,-1,9,90,11}
   //2. 假定第一个元素就是最大值,下标就是0
   //3. 然后从第二个元素开始循环比较,如果发现有更大值,则交换
   var intArr [6]int = [...]int {1,-1,9,90,11,9000}
   maxVal := intArr[0]
   maxValIndex := 0
   for i := 1; i < len(intArr); i++ {
      //从第二个元素开始循环比较,如果发现有更大,则交换
      if maxVal < intArr[i] {
         maxVal = intArr[i]
         maxValIndex = i
      }
   }
   fmt.Printf("maxVal = %v maxValIndex = %v", maxVal, maxValIndex)
}
//输出:maxVal = 9000 maxValIndex = 5

请求出一个数组的和和平均值。for-range

func main() {
   //思路
   //1. 声明一个数组 var intArr[5] = [...]int{1,-1,9,90,11}
   //2. 求出和sum
   //3. 求出平均值
   var intArr [5]int = [...]int{1, -1, 9, 90, 12}
   sum := 0
   for _,val := range intArr {
      //累计求和
      sum += val
   }
   //如何让平均值保留到小数
   fmt.Printf("sum = %v 平均值 = %v", sum, float64(sum) / float64(len(intArr)) )
}
//输出:sum = 111 平均值 = 22.2

要求:随机生成五个数,并将其反转打印,复杂应用

import (
   "fmt"
   "math/rand"
   "time"
)

func main() {
   //思路
   //1. 随机生成5个数,rand.Intn()函数
   //2. 当我们得到随机数后,就放到一个数组int数组
   //3. 反转打印,交换的次数是len/2,倒数第一个和第一个元素交换,倒数第二个和第二个元素交换
   var intArr [5]int
   //为了每次生成的随机数都不一样,我们需要给一个seed值
   len := len(intArr)
   rand.Seed(time.Now().UnixNano())
   for i := 0; i < len; i++ {
      intArr[i] = rand.Intn(100)  //0 <= n < 100
   }
   fmt.Println("交换前",intArr)
   //反转打印,交换的次数是 len / 2
   //倒数第一个和第一个元素交换,倒数第二个和第二个元素交换
   temp := 0 //做一个临时变量
   for i := 0; i < len / 2; i++ {
      temp = intArr[len - 1 - i]
      intArr[len - 1 -i] = intArr[i]
      intArr[i] = temp
   }
   fmt.Println("交换后",intArr)
}
//输出:交换前 [24 15 90 17 6]
//交换后 [6 17 90 15 24]

数组练习题

题目要求:

跳水比赛 8个评委打分,运动员的成绩去掉一个最高分,去掉一个最低分,剩下的6个分数的平均分就是最后得分,使现

(1)请把最高分,最低分的评委找出

(2)找出最佳评委和最差评委。最佳评委是最后得分差距最小,最差评委最后得分差距最大

分析:

设计一个函数求最高分 最低分 平均分 需要考虑存在多个最低分和最高分的情况

找最有裁判和最差裁判使用abs() 以及切片完成 将绝对值传入到切片中再遍历

package main

import (
   "fmt"
   "math")
func max(array  *[8]float64) (mx float64,mi float64,avg float64){
   max := 0.0
   for i := 0; i < len(array); i++ {
      if (*array)[i] > max {
         max = (*array)[i]
      }
   }
   min := max
   for i := 0; i < len(array); i++ {
      if (*array)[i] < min  {
         min = (*array)[i]
      }
   }
   mx = max
   mi = min
   sum := 0.0
   maxcount,mincount :=0.0,0.0
   for i := 0; i < len(array); i++ {
       //判断最大值和最小值出现的次数 1次时直接去掉  多次是需要加上去
      if (*array)[i] == max {
         maxcount +=1
      }
      if (*array)[i] == min{
         mincount +=1
      }
      //算出不包含任意一次不包含 最大值、最小值的和
      if (*array)[i] != max && (*array)[i] != min{
         sum += (*array)[i]
      }

   }
   //fmt.Println(maxcount,mincount)
   //处理出现多次最大值或者最小值
   if  mincount > 1.0 && maxcount > 1.0{
      sum += (max*(maxcount-1)+min*(mincount-1))
   }else if mincount > 1.0 && maxcount == 1.0{
      sum += (min*(mincount-1))
   }else if mincount ==1.0  && maxcount > 1.0{
      sum += (max*(maxcount-1))
   }else {
       sum += 0
   }
   avg = sum/6.0
   return  mx,min,avg}

func Best(array1  *[8]float64, arry2 []float64, avg float64) {

   for i := 0; i < len(array1); i++ {
      arry2 = append(arry2, math.Abs((*array1)[i]-avg))
   }
   max  := 0.0
   for j :=0;j < len(arry2);j++{
      if arry2[j] > max{
         max = arry2[j]
      }
   }
   min := max
   for i := 0; i < len(arry2); i++ {
      if arry2[i] < min  {
         min = arry2[i]
      }
   }
   for i := 0; i < len(arry2); i++ {
      if arry2[i] == min {
         fmt.Printf("最优秀评分者为第%v位裁判,评分:%v 和平均分相差%v\n",i+1,(*array1)[i],min)
      }
   }

   for i := 0; i < len(arry2); i++ {
      if arry2[i] == max  {
         fmt.Printf("评分差距最大者为第%v位裁判,评分:%v和平均分相差%v\n",i+1,(*array1)[i],max)
      }
   }}

var Socre [8]float64
var Socreabs = make([]float64,0,0)
func main() {
   //输入8个裁判的分数
   for  i := 0;i<len(Socre);i++{
      fmt.Printf("请输入第%v位裁判的的评分:\n",i+1)
      fmt.Scanln(&Socre[i])
   }

   max,min,avg :=max(&Socre)
   fmt.Println(Socre)
   fmt.Printf("最高分为:%v,最低分为:%v 平均分为:%v\n",max,min,avg)
   //知道最大分  最小分 找最大分、最小分的裁判
   for k :=0;k<len(Socre);k++{
      if Socre[k] == max{
         fmt.Printf("最高分为:%v,第%v位裁判\n",max,k+1)
      }else if Socre[k] == min {
         fmt.Printf("最低分:%v,第%v位裁判\n",min,k+1)
      }
   }
   Best(&Socre,Socreabs,avg)

}

切片

切片的英文是slice 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制 切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度len(slice)都一样 切片的长度是可以变化的,因此切片是一个可以动态变化的数组

var 切片名 []类型
比如: var  a  []int

func main()  {
   //演示切片的基本使用
   var intArr [5]int = [...]int {1,22,33,66,99}
   //声明/定义一个切片
   //1. slice := intArr[1:3]
   //2. intArr[1:3]表示slice引用到intArr这个数组
   //3. 引用intArr数组的起始下标为1,最后的下标为3(但是不包含3)
   slice := intArr[1:3]
   fmt.Println("intArr = ",intArr)
   fmt.Println("slice 的元素是 = ",slice) // 22,33
   fmt.Println("slice 的元素个数 = ",len(slice)) // 2
   fmt.Println("slice 的容量 = ", cap(slice)) //切片的容量是可以动态变化
}
//输出:intArr =  [1 22 33 66 99]
//slice 的元素是 =  [22 33]
//slice 的元素个数 =  2
//slice 的容量 =  4

切片在内存中形式【重要】

go语言系列-从数组到map go 第5张

对上面的分析图总结

slice的确是一个引用类型
slice从底层来说,其实就是一个数据结构(struct结构体)
	type slice struct {
		ptr *[2]int
		len int
		cap int
	}

切片的使用

方式1:定义一个数组,然后让切片去引用一个已经创建好的数组
func main()  {
   //演示切片的基本使用
   var intArr [5]int = [...]int {1,22,33,66,99}
   //声明/定义一个切片
   //1. slice := intArr[1:3]
   //2. intArr[1:3]表示slice引用到intArr这个数组
   //3. 引用intArr数组的起始下标为1,最后的下标为3(但是不包含3)
   slice := intArr[1:3]
   fmt.Println("intArr = ",intArr)
   fmt.Println("slice 的元素是 = ",slice) // 22,33
   fmt.Println("slice 的元素个数 = ",len(slice)) // 2
   fmt.Println("slice 的容量 = ", cap(slice)) //切片的容量是可以动态变化
}
//输出:intArr =  [1 22 33 66 99]
//slice 的元素是 =  [22 33]
//slice 的元素个数 =  2
//slice 的容量 =  4

方式2:通过make来创建切片
var 切片名 []type = make([]type,len,[cap])
参数说明:
	type:就是数据类型
	len :大小
	cap :指定切片容量,可选,如果分配了cap,则要求cap >= len 
func main() {
   //演示切片的使用 make
   var slice []float64 = make([]float64, 5, 10)
   slice[1] = 10
   slice[3] = 20
   //对于切片,必须make使用
   fmt.Println(slice)
   fmt.Println("slice的size = ",len(slice))
   fmt.Println("slice的cap  = ",cap(slice))
}
//输出:[0 10 0 20 0]
//slice的size =  5
//slice的cap  =  10

go语言系列-从数组到map go 第6张

对上面代码的小结:
1)通过make方式创建切片可以指定切片的大小和容量
2)如果没有给切片的各个元素赋值,那么就会使用默认值[int, float => 0 string => “ ” bool => false]
3)通过make方式创建的切片对应的数组是由make底层维护,对外不可见,即只能通过slice去访问各个元素

方式3:定义一个切片,直接就指定具体数组,使用原理类似make的方式
func main() {
   var strSlice []string = []string {"zisefeizhu","zhujingxing","mayike"}
   fmt.Println("strSlice = ", strSlice)
   fmt.Println("strSlice size = ",len(strSlice))
   fmt.Println("strSlice cap = ",cap(strSlice))
}
//输出:strSlice =  [zisefeizhu jingxing mayike]
//strSlice size =  3
//strSlice cap =  3

方式1和方式2的区别(面试)
	方式1是直接引用数组,这个数组是事先存在的,程序员是可见的
	方式2是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是看不见的,make创建切片的示意图

go语言系列-从数组到map go 第7张

切片的遍历

func main()  {
   //使用常规的for循环遍历切片
   var arr [5]int = [...]int {10, 20, 30, 40, 50}
   slice := arr[1:4] // 20, 30, 40
   for i := 0; i < len(slice); i++ {
      fmt.Printf("slice[%v] = %v \t",i , slice[i])
   }
   fmt.Println()

   //使用for - range 方式遍历切片
   for i, v := range slice {
      fmt.Printf("i = %v v = %v \n",i ,v)
   }
}

切片使用的注意事项和细节

slice扩充缩容会有内存申请释放也是开销,且扩容好像是1.25倍
切片初始化时 var slice = arr[startIndex:endIndex]
	说明:从arr数组下标为startIndex,取到下标为endIndex的元素(不含arr[endIndex])
切片初始化时,仍然不能越界。范围在[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[:]
cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素
切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用
切片可以继续切片
	func main()  {
   	var arr [5]int = [...]int {10, 20, 30, 40, 50}
   	slice := arr[1:4] // 20, 30, 40
   	slice2 := slice[1:2] // slice [20,30,40] [30]
   	slice2[0] = 100 //因为arr slice 和slice2 指向的数据空间是一个,因此slice2[0] =100
   	fmt.Println("slice2 = ",slice2)
   	fmt.Println("slice = ",slice)
   	fmt.Println("arr = ",arr)
	}
append内置函数,可以对切片进行动态追加
	func main()  {
  	 //用append内置函数,可以对切片进行动态追加
   	var slice []int = []int {100,200,300}
   	//通过append直接给slice追加具体的元素
   	slice = append(slice,400,500,600)
  	fmt.Println("slice",slice) //100, 200, 300, 400, 500, 600
   	//通过append将切片slice 追加给slice
   	slice = append(slice,slice...)   
  	fmt.Println("slice",slice) ////slice [100 200 300 400 500 600 100 200 300 400 500 600]
  }
	切片append操作的底层原理分析
		切片append操作的本质就是对数组扩容
		go底层会创建一下新的数组newArr(安装扩容后大小)
		将slice原来包含的元素拷贝到新的数组newArr
		slice 重新引用到newArr
		注意newArr是在底层来维护的,程序员不可见

go语言系列-从数组到map go 第8张

切片的拷贝操作
	切片使用copy内置函数完成拷贝,举例说明
	func main()  {
   	//切片的拷贝操作
   	//切片使用copy内置函数完成拷贝,举例说明
   	var slice []int = []int {1,2,3,4,5}
   	var slice2 = make([]int,10)
   	copy(slice2,slice)
   	fmt.Println("slice = ",slice)  //slice =  [1 2 3 4 5]
   	fmt.Println("slice2 = ",slice2) //slice2 =  [1 2 3 4 5 0 0 0 0 0]
	}
	copy(para1,para2)参数的数据类型是切片
	按照上面的代码来看,slice和slice2的数据空间是独立,相互不影响,也就是说slice[0] = 999,slice5[0] 仍然是1
关于拷贝的注意事项
	func main()  {
   	var a []int = []int {1,2,3,4,5}
   	var slice = make([]int,1)
   	fmt.Println(slice)
   	copy(slice,a)
   	fmt.Println(slice)
	}
	//输出:[0]
	//[1]	
切片是引用类型,所以在传递时,遵守引用传递机制。看两段代码,并分析底层原理

go语言系列-从数组到map go 第9张

string和slice

string底层是一个byte数组,因此string也可以进行切片处理

func main(){
   str := "hello@zisefeizhu"
   //使用切片获取到zisefeizhu
   slice := str[6:]
   fmt.Println("slice = ",slice)
}
//输出:slice =  zisefeizhu

string和切片在内存的形式,以”abcd”画出内存示意图 go语言系列-从数组到map go 第10张 string是不可变的,也就是说不能通过str[0] = ‘z’ 方式来修改字符串 go语言系列-从数组到map go 第11张 如果需要修改字符串,可以先将string → []byte /或者 []rune → 修改 → 重写转成string

如果需要修改字符串,可以先将string -> []byte  /或者  []rune -> 修改 -> 重写转成string
   //"hello@zisefeizhu" => 改成 "zello@zisefeizhu"
   arr1 := []byte(str)
   arr1[0] = 'z'
   str = string(arr1)
   fmt.Println("str = ",str)
   //细节:我们转成[]byte后,可以处理英文和数字,但是不能处理中文
   //原因是[]byte字节来处理,而一个汉字,是3个字节,因此就会出现乱码
   //解决方法是 将 string 转成 []rune 即可,因为[]rune 是按字符处理,兼容汉字
   arr2 := []rune(str)
   arr2[0] = '北'
   str = string(arr1)
   fmt.Println("str = ", str)
}
//输出:slice =  zisefeizhu
//str =  zello@zisefeizhu
//str =  zello@zisefeizhu

切片练习题

说明:编写一个函数 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

package main

import "fmt"

func fbn(n int) ([]uint64) {
   //声明一个切片,切片大小n
   fbnSlice := 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()  {
   /*
   1)可以接收一个n int
   2)能够将斐波那契的数列放到切片中
   3)提示,斐波那契的数列形式:
   arr[0] = 1; arr[1] = 1; arr[2] = 2; arr[3] = 3; arr[4] = 5; arr[5] = 8
   思路
   1. 声明一个函数fbn(n int) ([]uint64)
   2. 编程fbn(n int) 进行for循环来存放斐波那契的数列 0 =》1  1 =》 1
    */
   fnbSlice := fbn(20)
   fmt.Println("fnbSlice = ",fnbSlice)
}
//输出:fnbSlice =  [1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765]

排序

排序

排序是将一组数据,依指定的顺序进行排序的过程

排序的分类
1)内部排序:
	指将需要处理的所有数据都加载到内部存储器中进行排序
	包括(交换式排序法、选择式排序法和插入式排序法);
2)外部排序法
	数据量过大,无法全部加载到内存中,需要借助外部存储进行排序
	包括(合并排序法和直接合并排序法)

冒泡排序的思路分析

go语言系列-从数组到map go 第12张 go语言系列-从数组到map go 第13张

冒泡排序实现

//冒泡排序
func BubbleSort(arr *[5]int)  {
   fmt.Println("排序前arr = ",(*arr))
   temp := 0 //临时变量(用于做交换)

   //冒泡排序:一步一步推导出来的
   for i := 0; i < len(*arr) - 1; i++ {
      for j := 0; j < len(*arr) -1 - i; j++ {
         if (*arr)[j] < (*arr)[j + 1] {
            //交换
            temp = (*arr)[j]
            (*arr)[j] = (*arr)[j + 1]
            (*arr)[j + 1] = temp
         }
      }
   }
   fmt.Println("排序后arr  = ",(*arr))
}
func main()  {
   //定义数组
   arr := [...]int {24,69,80,57,13}
   //将数组传递给一个函数,完成排序
   BubbleSort(&arr)
   fmt.Println("main arr = ",arr) //有序? 是有序的
}
//输出:排序前arr =  [24 69 80 57 13]
//排序后arr  =  [80 69 57 24 13]
//main arr =  [80 69 57 24 13]

优化
//冒泡排序
func BubbleSort(arr []int) []int {
   fmt.Println("排序前arr = ", arr)
   flag := true
   //冒泡排序:一步一步推导出来的
   for i := 0; i < len(arr) - 1; i++ {
      for j := 0; j < len(arr) -1 - i; j++ {
         if arr[j] < arr[j + 1] {
            //交换
            Swap(arr, j , j+1)
            flag = false
         }
      }
      //优化不必要的交换
      if flag {
         break
      }
   }
   return arr
}

func Swap(arr []int, i int, j int )  {
   temp := arr[i]
   arr[i] = arr[j]
   arr[j] = temp
}

func main()  {
   //定义数组
   arr := []int {24,69,80,57,13}
   //将数组传递给一个函数,完成排序
   num := BubbleSort(arr)
   fmt.Println("main num = ",num)
}
//排序前arr =  [24 69 80 57 13]
//main num =  [80 69 57 24 13]

冒泡排序练习题

package main
//要求:随机生成5个元素的数组,并使用冒泡排序对其排序  从小到大
//思路分析:
//随机数用math/rand生成为了更好的保证其不会重复 使用 rand.New(rand.NewSource(time.Now().UnixNano()))并定义一个随机生成函数
//用冒泡排序对其排序
import (
   "fmt"
   "math/rand"
   "time"
)

var  arrnum [5]int = [5]int{109,137,49,190,87}
//定义冒泡函数
//重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)
// 错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成
func BubbleSort( arrary *[5]int){
   //第一次比较
   fmt.Println("排序前arr=",(*arrary))
   tmp :=0
   for  j := 0 ; j <len(arrary)-1 ;j++{
      for  i :=0;i <len(arrary)-1-j ;i++ {
         if arrary[i] > arrary[i+1]{
            tmp = arrary[i]
            arrary[i] = arrary[i+1]
            arrary[i+1] = tmp
         }
      }
   }

   fmt.Println("排序后arr=",(*arrary))

}


var  Arrname  [5]int

func main() {
   r := rand.New(rand.NewSource(time.Now().UnixNano()))//生成随机数字
   for  i := 0; i < len(Arrname) ; i++ {
      Arrname[i] = r.Intn(20000) //指定生成随机数的范围
   }
   BubbleSort(&Arrname)

}

查找

在Go中,常用的查找有两种:

  1. 顺序查找

  2. 二分查找(该数组是有序)

案例演示

1)有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王

猜数游戏:从键盘中任意输入一个名称,判断数列中是否包含此名称【顺序查找】

func main()  {
   names := [4]string{"白眉鹰王","金毛狮王","紫衫龙王","青翼蝠王"}
   var heroName = ""
   fmt.Println("请输入要查找的人名...")
   fmt.Scanln(&heroName)
   //顺序查找:第一种方式
   for i := 0; i < len(names); i++ {
      if heroName == names[i] {
         fmt.Printf("找到%v 下标%v \n",heroName,i)
         break
      } else if i == (len(names) -1 ) {
         fmt.Printf("没有找到%v \n",heroName)
      }
   }

   //顺序查找:第二种方式【推荐...】
   index := -1
   for i := 0; i < len(names); i++ {
      if heroName == names[i] {
         index = i //将找到的值对应的下标赋给index
         break
      }
   }
   if index != -1 {
      fmt.Printf("找到%v,下标%v \n",heroName,index)
   } else {
      fmt.Println("没有找到",heroName)
   }
}
//输出:请输入要查找的人名...  白眉鹰王   找到白眉鹰王 下标0   找到白眉鹰王,下标0 
  1. 请对一个有序数组进行二分查找 {1,8,10,89,1000,1234},输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示”没有这个数”【会使用到递归】

二分查找的思路分析 go语言系列-从数组到map go 第14张

//二分法查找
/*
   二分查找思路:比如要查找的数是findVal
   1. arr是一个有序数组,并且是从小到大排序
   2. 先找到中间的下标middle = (leftIndex + rightIndex)/2,然后让中间下标的值和findVal进行比较
   2.1  如果arr[middle] > findVal  就应该向 leftIndex --- (middle - 1)
   2.2  如果arr[middle] < findVal  就应该向 (middle + 1) --- rightIndex
   2.3  如果arr[middle] == findVal  就找到
   2.4  上面的2.1 2.2 2.3 的逻辑会递归执行
   3. 想一下,怎么样的情况下,就说明找不到【分析出退出递归的条件!!】
   if leftIndex > rightIndex {
      //找不到...
      return ...
   }
 */

func BinaryFind(arr *[6]int, leftIndex int, rightIndex int, findVal int)  {
   //判断leftIndex是否大于rightIndex
   if leftIndex > rightIndex {
      fmt.Println("找不到")
      return
   }
   //先找到 中间的下标
   middle := (leftIndex + rightIndex) / 2
   if (*arr)[middle] > findVal {
      //说明要查找的数,应该在leftIndex -- (middle - 1)
      BinaryFind(arr, leftIndex, middle - 1, findVal)
   } else if (*arr)[middle] < findVal {
      //说明要查找的数,应该在middle + 1 -- rightIndex
      BinaryFind(arr, middle + 1, rightIndex, findVal)
   } else {
      //找到了
      fmt.Printf("找到了,下标为%v \n",middle)
   }
}
func main()  {
   arr := [6]int {1,8,89,1000,1234}
   //测试
   BinaryFind(&arr,0,len(arr) - 1, 1234)
}
//输出:找到了,下标为4 

二维数组

请用二维数组输出如下图形 go语言系列-从数组到map go 第15张

func main()  {
   //定义/声明二维数组
   var arr [4][6]int
   //赋初值
   arr[1][2] = 1
   arr[2][1] = 2
   arr[2][3] = 3
   //遍历二维数组,按照要求输出图形
   for i := 0; i < 4; i++ {
      for j := 0; j < 6; j++ {
         fmt.Print(arr[i][j]," ")
      }
      fmt.Println()
   }
}
//0 0 0 0 0 0 
//0 0 1 0 0 0 
//0 2 0 3 0 0 
//0 0 0 0 0 0 

二维数组在内存的存在形式

go语言系列-从数组到map go 第16张

二维数组在声明/定义时的写法

1)var 数组名 [大小][大小]类型 = [大小][大小]类型{{初值...},{初值...}}
2)var 数组名 [大小][大小]类型 = [...][大小]类型{{初值...},{初值...}}
3)var 数组名  = [大小][大小]类型{{初值...},{初值...}}
4)var 数组名 = [...][大小]类型{{初值...},{初值...}}

二维数组的遍历

func main()  {
   //演示二维数组的遍历
   var arr = [2][3]int{{1,2,3},{4,5,6}}
   //for循环遍历
   for i := 0; i < len(arr); i++ {
      for j := 0; j < len(arr[i]); j++ {
         fmt.Printf("%v\t",arr[i][j])
      }
      fmt.Println()
   }
   //for-range遍历二维数组
   for i, v := range arr {
      for j, v2 := range v {
         fmt.Printf("arr[%v][%v]=%v\t",i,j,v2)
      }
      fmt.Println()
   }
}

二维数组的应用案例

定义二维数组,用于保存三个班,每个班五名同学成绩,

并求出每个班级平均分、以及所有班级平均分

func main()  {
   //定义二维数组,用于保存三个班,每个班五名同学成绩,
   //并求出每个班级平均分、以及所有班级平均分
   //1.定义二维数组
   var scores [3][5]float64
   //2.循环的输入成绩
   for i := 0; i < len(scores); i++ {
      for j := 0; j < len(scores[i]); j++ {
         fmt.Printf("请输入第%d班的第%d个学生的成绩\n",i+1, j+1)
         fmt.Scanln(&scores[i][j])
      }
   }
   //fmt.Println(scores)
   //3.遍历输出成绩后的二维数组,统计平局分
   totalSum := 0.0 //定义一个变量,用于累计所有班级的总分
   for i := 0; i < len(scores); i++ {
      sum := 0.0 //定义一个变量,用于累计各个班级的总分
      for j := 0; j < len(scores[i]); j++ {
         sum += scores[i][j]
      }
      totalSum += sum
      fmt.Printf("第%d班级的总分为%v,平均分%v\n", i + 1, sum, sum / float64(len(scores[i])))
   }
   fmt.Printf("所有班级的总分为%v,所有班级平均分%v\n", totalSum, totalSum / 15 )
}

二维数组练习题

转置概念:矩阵的行列互换得到的新矩阵称为转置矩阵,而二维数组就是我们通常说的矩阵。

需求:使用Go语言方法实现二维数组(3*3)的矩阵的转置

转置前:

​ [ 0, 1, 2]

​ [ 4, 5, 6]

​ [ 8, 9, 10]

转置后

​ [ 0, 4, 8]

​ [ 1, 5, 9]

​ [ 2, 6, 10]

type   Num struct {

}

func (array  Num ) Upserver(Aaaay3 [3][3]int)  {
   for i :=0; i<len(Aaaay3);i++{
      for  j:=0;j<i;j++{
         Aaaay3[i][j],Aaaay3[j][i] = Aaaay3[j][i],Aaaay3[i][j]
      }
   }
   fmt.Println(Aaaay3)
}

func (array  Num ) Upserver2(Aaaay3 [3][3]int)  {
   temparry :=[3][3]int{}
   for i :=0; i<len(Aaaay3);i++{
      for  j:=0;j<i;j++{
         temparry[i][j]=Aaaay3[i][j]
         Aaaay3[i][j] =Aaaay3[j][i]
         Aaaay3[j][i]=temparry[i][j]
      }
   }
   fmt.Println(Aaaay3)
}

func main() {
   arrinfo :=Num{

   }
   aeey :=[3][3]int{
      {0, 1, 2} ,   /*  第一行索引为 0 */
      {4, 5, 6} ,   /*  第二行索引为 1 */
      {8, 9, 10}}
   fmt.Println(aeey)
   fmt.Println("****")
   arrinfo.Upserver(aeey)
   arrinfo.Upserver2(aeey)
}

Map

map是key-value数据结构,又称为字段或者关联数组。类似其它编程语言的集合,在编程中是经常使用到的

v 内部实现

Map是给予散列表来实现,就是我们常说的Hash表,所以我们每次迭代Map的时候,打印的Key和Value是无序的,每次迭代的都不一样,即使我们按照一定的顺序存在也不行。

Map的散列表包含一组桶,每次存储和查找键值对的时候,都要先选择一个桶。如何选择桶呢?就是把指定的键传给散列函数,就可以索引到相应的桶了,进而找到对应的键值。

这种方式的好处在于,存储的数据越多,索引分布越均匀,所以我们访问键值对的速度也就越快,当然存储的细节还有很多,大家可以参考Hash相关的知识,这里我们记住Map存储的是无序的键值对集合

map的声明

var 变量名 map[keytype]valuetype
key可以是什么类型
	Go中的map的key可以是很多种类型,比如bool、数字、string、指针、channel,还可以是只包含前面几个类型的 接口、结构体、数组
	通常key为int、string
	注意:slice、map还有function不可以,因为这几个没法用 == 来判断
valuetype可以是什么类型
	valuetype的类型和key基本一样
	通常为:数字(整数,浮点数)、string、map、struct

map声明的举例:
	var a map[string]string
	var a map[string]int
	var a map[int]string
	var a map[string]map[string]string
	注意:声明是不会分配内存的,初始化需要make,分配内存后才能赋值和使用

func main()  {
   //map的声明和注意事项
   var a map[string]string
   //在使用map前,需要先make,make的作用就是给map分配数据空间
   a = make(map[string]string,10)
   a["no1"] = "松江"
   a["no2"] = "无用"
   a["no1"] = "武松"
   a["no3"] = "无用"
   fmt.Println(a)
}
//输出:map[no1:武松 no2:无用 no3:无用]
对上面代码的说明
	1)map在使用前一定要make
	2)map的key是不能重复的,如果重复了,则以最后这个key-value为准
	3)map的value是可以相同的
	4)map的key-value是无序的
	5)make内置函数数目

map的使用

方式1:
func main()  {
   //第一种使用方式
   var a map[string]string
   //在使用map前,需要先make,make的作用就是给map分配数据空间
   a = make(map[string]string,10)
   a["no1"] = "松江"
   a["no2"] = "无用"
   a["no1"] = "武松"
   a["no3"] = "无用"
   fmt.Println(a)
}

方式2:
func main()  {
   //第二种方式
   cities := make(map[string]string)
   cities["no1"] = "北京"
   cities["no2"] = "天津"
   cities["no3"] = "上海"
   fmt.Println(cities)
//输出:map[no1:北京 no2:天津 no3:上海]
  
方式3:
func main()  {
	//第三种方式
	heroes := map[string]string {
		"her01" : "宋江",
		"her02" : "吴用",
		"her03" : "林冲",
	}
	heroes["her04"] = "武松"
	fmt.Println("heroes = ",heroes)
}
//heroes =  map[her01:宋江 her02:吴用 her03:林冲 her04:武松] 

map的增删改查操作

map增加和更新 map["key"] = value //如果key还没有,就是增加,如果key存在就是修改

func main(){
   cities := make(map[string]string)
   cities["no1"] = "北京"
   cities["no2"] = "天津"
   cities["no3"] = "上海"
   fmt.Println(cities)
   //因此no3 这个key已经存在,因此下面的这句就是修改
   cities["no3"] = "上海~"
   fmt.Println(cities)
}
//输出:map[no1:北京 no2:天津 no3:上海]
//map[no1:北京 no2:天津 no3:上海~]

map删除

delete(map,"key"),delete是一个内置函数,如果key存在,就删除该key-value,如果key不存在,不操作,但是也不会报错 go语言系列-从数组到map go 第17张

func main(){
   cities := make(map[string]string)
   cities["no1"] = "北京"
   cities["no2"] = "天津"
   cities["no3"] = "上海"
   fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海]
   //因此no3 这个key已经存在,因此下面的这句就是修改
   cities["no3"] = "上海~"
   fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海~]
   //演示删除
   delete(cities,"no1")
   fmt.Println(cities)  //map[no2:天津 no3:上海~]
   //当delete指定的key不存在时,删除不会操作,也不会报错
   delete(cities,"no4")
   fmt.Println(cities)  //map[no2:天津 no3:上海~]
  
如果要删除map的所有key,没有一个专门的方法一次删除,可以遍历一下key,逐个删除或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收
func main(){
   cities := make(map[string]string)
   cities["no1"] = "北京"
   cities["no2"] = "天津"
   cities["no3"] = "上海"
   fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海]
   //因此no3 这个key已经存在,因此下面的这句就是修改
   cities["no3"] = "上海~"
   fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海~]
   //演示删除
   delete(cities,"no1")
   fmt.Println(cities)  //map[no2:天津 no3:上海~]
   //当delete指定的key不存在时,删除不会操作,也不会报错
   delete(cities,"no4")
   fmt.Println(cities)  //map[no2:天津 no3:上海~]
   //如果希望一次性删除所有的key
   //1. 遍历所有的key,遍历逐一删除
   //2. 直接make一个新的空间
   cities = make(map[string]string)
   fmt.Println(cities)  //map[]
}  

map查找

func main(){
   cities := make(map[string]string)
   cities["no1"] = "北京"
   cities["no2"] = "天津"
   cities["no3"] = "上海"
   fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海]
   //因此no3 这个key已经存在,因此下面的这句就是修改
   cities["no3"] = "上海~"
   fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海~]
   //演示map 的查找
   va1, ok := cities["no2"]
   if ok {
      fmt.Printf("有no2 key值为%v\n",va1)  //有no2 key值为天津
   } else {
      fmt.Printf("没有no2 key\n")
   }
}

对上面代码的说明:
说明:如果cities这个map中存在”no2”,那么ok就会返回true,否则返回false

map遍历

案例演示相对复杂的map遍历:该map的value又是一个map

说明:map的遍历使用for-range的结构遍历

func main()  {
   //使用for-range遍历map
   cities := make(map[string]string)
   cities["no1"] = "北京"
   cities["no2"] = "天津"
   cities["no3"] = "上海"
   for k,v := range cities {
      fmt.Printf("k = %v v = %v\n",k,v)
   }
   //使用for-range遍历一个结构比较复杂的map
   studentMap := make(map[string]map[string]string)
   studentMap["stu01"] = make(map[string]string, 3)
   studentMap["stu01"]["name"] = "tom"
   studentMap["stu01"]["sex"] = "男"
   studentMap["stu01"]["address"] = "北京长安街"

   studentMap["stu02"] = make(map[string]string, 3)  //这句话不能少!!!
   studentMap["stu02"]["name"] = "mary"
   studentMap["stu02"]["sex"] = "女"
   studentMap["stu02"]["address"] = "上海黄埔江"

   for k1, v1 := range studentMap {
      fmt.Println("k1 = ",k1)
      for  k2, v2 := range v1 {
         fmt.Printf("\t k2 = %v v2 = %v \n",k2,v2)
      }
      fmt.Println()
   }
}
//输出:k = no1 v = 北京
//k = no2 v = 天津
//k = no3 v = 上海
//k1 =  stu01
//  k2 = name v2 = tom 
//  k2 = sex v2 = 男 
//  k2 = address v2 = 北京长安街 
//
//k1 =  stu02
//  k2 = name v2 = mary 
//  k2 = sex v2 = 女 
//  k2 = address v2 = 上海黄埔江 

map的长度

go语言系列-从数组到map go 第18张

func main()  {
   //使用for-range遍历map
   cities := make(map[string]string)
   cities["no1"] = "北京"
   cities["no2"] = "天津"
   cities["no3"] = "上海"
   for k,v := range cities {
      fmt.Printf("k = %v v = %v\n",k,v)
   }
   fmt.Println(len(cities))  //3
}

map切片

切片的数据类型如果是map,则我们称为slice of map,map切片,这样使用则map个数就可以动态变化了

案例演示

要求:使用一个map来记录monster的信息name和age,也就是说一个monster对应一个map,并且妖怪的个数可以动态的增加=》map切片

package main

import (
   "fmt"
   _ "unicode"
)

func main()  {
   var monsters []map[string]string
   monsters = make([]map[string]string,2) //准备放入两个妖怪
   //2. 增加第一个妖怪的信息
   if monsters[0] == nil {
      monsters[0] = make(map[string]string,2)
      monsters[0]["name"] = "牛魔王"
      monsters[0]["age"] = "500"
   }

   if monsters[1] == nil {
      monsters[1] = make(map[string]string, 2)
      monsters[1]["name"] = "玉兔精"
      monsters[1]["age"] = "400"
   }
   //下面这个写法越界
   //if monsters[2] == nil {
   //    monsters[2] = make(map[string]string, 2)
   //    monsters[2]["name"] = "狐狸精"
   //    monsters[2]["age"] = "300"
   // }

   //这里需要使用到切片的append函数,可以动态的增加monster
   //1. 先定义monster信息
   newMonster := map[string]string {
      "name" : "新的妖怪-孙悟空",
      "age" : "1500",
   }
   monsters = append(monsters,newMonster)

   fmt.Println(monsters)
}
//输出:[map[age:500 name:牛魔王] map[age:400 name:玉兔精] map[age:1500 name:新的妖怪-孙悟空]]

map排序

Go中没有一个专门的方法针对map的key进行排序

Go中的map默认是无序的,注意也不是按照添加的顺序存放的,每次遍历,得到的输出可能不一样

Go中map的排序,是先将key进行排序,然后根据key值遍历输出即可

案例演示

package main

import (
   "fmt"
   "sort"
)
func main()  {
   //map的排序
   map1 := make(map[int]int,10)
   map1[10] = 100
   map1[1] = 13
   map1[4] = 56
   map1[8] = 90
   fmt.Println(map1)
   //如果按照map的key的顺序进行排序输出
   //1. 先将map的key放入到切片中
   //2. 对切片排序
   //3. 遍历切片,然后按照key来输出map的值
   var keys []int
   for k, _ := range map1 {
      keys = append(keys, k)
   }
   //排序
   sort.Ints(keys)
   fmt.Println(keys)
   for _, k := range keys {
      fmt.Printf("map1[%v] = %v \n", k, map1[k])
   }
}
//输出:map[1:13 4:56 8:90 10:100]
//[1 4 8 10]
//map1[1] = 13 
//map1[4] = 56 
//map1[8] = 90 
//map1[10] = 100 

map使用细节

map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map

func modify(map1 map[int]int)  {
   map1[10] = 900
}
func main()  {
   map1 := make(map[int]int)
   map1[1] = 90
   map1[2] = 88
   map1[10] = 1
   map1[20] = 2
   modify(map1)
   fmt.Println(map1)
}
//输出:map[1:90 2:88 10:900 20:2]

map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态的增长 键值对(key-value)

map的value也经常使用struct类,更适合管理复杂的数据(比前面value是一个map更好),比如value为Student结构体

type Stu struct {
	Name  string
	Age   int
	Address  string
}

func main()  {
	//3)map的value也经常使用struct类型,
	// 更适合管理复杂的数据(比前面value是一个map更好),
	// 比如value为Student结构体
	//1. map 的 key 为学生的学号,是唯一的
	//2. map的value 为结构体,包含学生的名字,年龄,地址
	students := make(map[string]Stu, 10)
	//创建2个学生
	stu1 := Stu{"tom", 18, "北京"}
	stu2 := Stu{"mary", 28, "上海"}
	students["no1"] = stu1
	students["no2"] = stu2

	fmt.Println(students)
	//遍历各个学生信息
	for k, v := range students {
		fmt.Printf("学生的编号是%v \n",k)
		fmt.Printf("学生的名字是%v \n",v.Name)
		fmt.Printf("学生的年龄是%v \n",v.Age)
		fmt.Printf("学生的地址是%v \n",v.Address)
	}
}
//map[no1:{tom 18 北京} no2:{mary 28 上海}]
//学生的编号是no1
//学生的名字是tom
//学生的年龄是18
//学生的地址是北京
//学生的编号是no2
//学生的名字是mary
//学生的年龄是28
//学生的地址是上海 

map练习题

演示一个key-value的value是map的案例

​ 比如:要存放3个学生信息,每个学生有name和sex信息

​ 思路: map[string]map[string]string

func main()  {
   studentMap := make(map[string]map[string]string)
   studentMap["stu01"] = make(map[string]string, 3)
   studentMap["stu01"]["name"] = "tom"
   studentMap["stu01"]["sex"] = "男"
   studentMap["stu01"]["address"] = "北京长安街"

   studentMap["stu02"] = make(map[string]string, 3)  //这句话不能少!!!
   studentMap["stu02"]["name"] = "mary"
   studentMap["stu02"]["sex"] = "女"
   studentMap["stu02"]["address"] = "上海黄埔江"

   fmt.Println(studentMap)  //map[stu01:map[address:北京长安街 name:tom sex:男] stu02:map[address:上海黄埔江 name:mary sex:女]]
   fmt.Println(studentMap["stu02"])  //map[address:上海黄埔江 name:mary sex:女]
   fmt.Println(studentMap["stu02"]["address"])  //上海黄埔江
}

编写一个函数modifyUser(users map[string]map[string]string,name string)完成上下述功能

  1. 使用map[string]map[string]string的map类型

  2. key:表示用户名,是唯一的,不可以重复

  3. 如果某个用户存在,就将其密码修改"888888",如果不存在就增加这个用户信息(包括昵称nickname和密码pwd)。

func modifyUser(users map[string]map[string]string,name string)  {
   //判断users中是否有name
   //v,ok := users[name]
   if users[name] != nil {
      //有这个用户
      users[name]["pwd"] = "888888"
   } else {
      //没有这个用户
      users[name] = make(map[string]string,2)
      users[name]["pwd"] = "888888"
      users[name]["nickname"] = "昵称~" + name //示意
   }
}
func main()  {
   users := make(map[string]map[string]string,10)
   users["smith"] = make(map[string]string,2)
   users["smith"]["pwd"] = "999999"
   users["smith"]["nickname"] = "小花猫"

   modifyUser(users,"tom")
   modifyUser(users,"mary")
   modifyUser(users,"smith")
   fmt.Println(users)
}
//输出:map[mary:map[nickname:昵称~mary pwd:888888] smith:map[nickname:小花猫 pwd:888888] tom:map[nickname:昵称~tom pwd:888888]]
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄