go language series - from the array to the map

Array

Array can store a plurality of the same type of data. Array is a data type, in Go, the array is a value type

A chicken farm chickens 6, their weight were 3kg, 5kg, 1kg, 3.4kg, 2kg, 50kg. Does this six chickens of total body weight is how much? The average weight?

使用传统的方法不利于数据的管理和维护
传统的方法不够灵活,因此我们引出需要学习的新的数据类型  ==》数组

//使用数组的方式来解决问题
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
使用数组来解决问题,增加程序的可维护性
而且方法代码更加清晰,也容易扩展

In the memory array layout

数组的地址可以通过数组名来获取 &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

Using an array of

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]
   }
}

Way to initialize an array of

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]

Iterate

方法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] = 林冲 
//元素的值 = 宋江
//元素的值 = 吴用
//元素的值 = 林冲

An array of notes and details of the use of

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

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

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

Array of Applications

Creates a byte array type elements 26, are placed 'A' - 'Z'. Use a for loop to access all the elements and print them out. Tip: The character data operation '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
}

Request the maximum value of an array, and with the corresponding subscript

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

And the average value of the request and an array. 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

Requirements: five randomly generated number, and reverse printing, complex applications

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]

An array of exercises

Topics requirements:

Diving competition eight judges scoring, athletes remove a maximum points, removing a minimum points, an average of six minutes remaining the score is the final score, so now

(1) Make the highest score, lowest score of the judges find

(2) identify the best and worst judges the judges. Best score of the judges is final gap between the minimum, maximum worst judges the final score gap

analysis:

Design a function evaluation highest score lowest score average to be considered where there are multiple lowest score and the highest score

Find the most worst referee and umpire use abs () and slice the completion of the absolute value passed into slices and then iterate

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

English is the slice slice
slice is a reference to an array slice is a reference type and therefore, during transfer, the transfer mechanism compliance by reference
use, and is similar to the array slice, slice traversal, access request elements and slice length len slice (slice) are the same
slice length can be varied, so may be a slice is a dynamic array

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

Slice in the form of memory [important]

The above summary of the analysis chart

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

Use slices

方式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

对上面代码的小结:
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创建切片的示意图

Traverse sections

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)
   }
}

Precautions sections and details of the use of

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是在底层来维护的,程序员不可见

切片的拷贝操作
	切片使用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]	
切片是引用类型,所以在传递时,遵守引用传递机制。看两段代码,并分析底层原理

string and slice

The bottom layer is a byte string array, so string slicing processing may be performed

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

string and memory in the form of slices, to "abcd" shown a schematic memory

string is immutable, that is to say can not str [0] = 'z' way to modify the string

, if the string needs to be modified, can first string -> [] byte / or [] Rune -> modify -> rewrite string converted into

如果需要修改字符串,可以先将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

Slice exercises

Description: write a function fbn (n int), required to complete

  1. You may receive one n int

  2. It can be Fibonacci series into slices

  3. Suggest that the number of columns in the form of Fibonacci:

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]

Sequence

Sequence

The sorting process is a set of data sorted by the order specified

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

Bubble sort of thinking analysis


Bubble sort to achieve

//冒泡排序
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]

Bubble Sort exercises

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)

}

Seek

In Go, look, there are two commonly used:

  1. Sequential search

  2. Binary search (which is an ordered array)

Case presentation

1) there is a series: Baimeiyingwang, Lion King, paclitaxel Dragon King, Bat Sowosky

Guessing game: input from the keyboard in any one name, number of columns determine whether to include the name of this order [to find]

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. Please ordered array to a binary search 1,8,10,89,1000,1234 {}, enter a number to see if the array is the presence of this number, and obtained subscript, if not prompt "no such number." [] will be used to recursively

Find analysis of binary thinking

//二分法查找
/*
   二分查找思路:比如要查找的数是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 

Two-dimensional array

Please use the graphical output following a two-dimensional array

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 

In the form of two-dimensional array of memory

Two-dimensional array wording in the declaration / definition

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

Traversing the two-dimensional array

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()
   }
}

Applications of two-dimensional array

Defined two-dimensional array, used to hold three classes, each class five student achievement,

And the average calculated for each class, and all classes average

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 )
}

Two-dimensional array of exercises

Transpose concept: a new matrix obtained by interchanging rows and columns of a matrix called the transposed matrix, and a two-dimensional array is what we usually say that the matrix.

Requirements: Transpose method using the Go language to achieve a two-dimensional array (3 * 3) matrix

Transpose ago:

​ [ 0, 1, 2]

​ [ 4, 5, 6]

​ [ 8, 9, 10]

After transpose

​ [ 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

key-value map is a data structure, also known as an associative array, or field. Like the other set of programming languages, programming is often used to

Internal v realization

Map is to give the hash table to achieve, is what we often say that the Hash table, so every time we iteration Map, Key and Value printing is disordered, each iteration is different, even if we exist in a certain order It does not work.

Map of the hash table contains a set of barrels, each store and find key-value pairs, when they have to choose a barrel. How to choose the barrel of it? The key is to pass the specified hash function, you can index into the appropriate bucket, and then find the corresponding key.

The advantage of this approach is that the more data stored, the more uniform distribution of the index, we access to the key rate sooner, of course, there are many details stored, we can refer to the relevant knowledge Hash, here we remember Map live storage are unordered collection of key-value pairs

map declaration

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内置函数数目

Use the 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 CRUD operations

map add and update
map [ "key"] = value // If the key has not been, is to increase, if the key is a change in the presence of

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:上海~]

Delete map

delete (map, "key"), delete a built-in function, if the key is present, remove the key-value, if the key does not exist, does not operate, but also not being given

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[]
}  

Find a 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 traversal

Case presentation relatively complex map traversal: The value of the map is a map

Description: map using structured traversal of traversal 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 = 上海黄埔江 

The length of the map

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 sections

If a data slice type map, then we called slice of map, map sections, so that the number used can be dynamically changed map

Case presentation

Requirements: a map information to record the name and Age monster, that a map corresponding to a monster, and the monster dynamically increasing number = "map sections

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 Sort

Go not in a special way for the sort of key map

Go is the default map disorder, attention is not stored in the order added, each iteration, the resulting output may be different

Go in the sorting map, is the first sort key, then the key value according to the output traversal

Case presentation

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 Details

After the map is a reference type, transmission type reference compliance mechanism, receiving a function map, modify, directly modify the original 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 capacity is reached, would like to map the elements increase, it will automatically expansion, and panic does not occur, that can map the dynamic growth of key (key-value)

The map value is often used struct type, it is more suitable for complex management data (a map is better than the previous value), such as value Student structure

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 exercises

Demonstrates a key-value is the value map case

For example: To store the three student information, each student has a name and sex information

​ 思路: 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"])  //上海黄埔江
}

Write a function modifyUser (users map [string] map [string] string, name string) to complete the following functions

  1. Use map [string] map [string] string type of map

  2. key: indicates that the user name is unique, can not be repeated

  3. If a user exists, it will modify their password "888888", if there is no increase in the user information (including the nickname nickname and password 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]]

Guess you like

Origin www.cnblogs.com/zisefeizhu/p/12628336.html