• go学习之数组与Map


    一、数组

    1.为什么需要数组

    问题:

    一个养鸡场有6只鸡,他们的体重分别是3kg .5kg 1kg 3.4kg 2kg 50kg请问这六只鸡的总体重是多少?平均体重是多少?请你编写一个程序

    传统方法:定义六个变量进行求值即可

    问题:不利于数据的管理和维护,不够灵活,我们需要使用新的数据类型数组

    数组介绍

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

    2.数组快速入门

    /*
    一个养鸡场有6只鸡,他们的体重分别是3kg .5kg 1kg 3.4kg 
    2kg 50kg请问这六只鸡的总体重是多少?平均体重是多少?
    请你编写一个程序
    */
    func main(){
     //使用数组来解决问题
     //1.定义一个数组
     var hens [6]float64
    //2.给数组的每个元素赋值操作,元素下标从0开始
    hens[0] =3.0 //hens数组的第一个元素赋值
    hens[1] =5.0
    hens[2] =1.0
    hens[3] =3.4
    hens[4] =2.0
    hens[5] =50.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("鸡的总体重是:%v,平均体重是%v",totalweight,avgweight)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    对上面代码总结

    1)使用数组解决问题,程序的可维护性增加

    2)而且的方法代码更加清晰,也容易扩展

    3、数组的定义和内存布局

    数组的定义

    var 数组名[数组大小] 数据类型
    var a[5]int
    赋初值 a[0]=1 a[1]=30 ...
    
    • 1
    • 2
    • 3

    数组内存(重要)

    func main(){
    	var intArr [3]int
    	//当我们定义完数组后,数组的各个元素有默认值0
    	fmt.Println(intArr)//[0 0 0]
    	fmt.Printf("数组的地址是:%p",&intArr)//数组的地址是:0xc0420082c0
          fmt.Printf("数组首地址是:%p",&intArr[0])
        数组的首地址是:0xc0420082c0
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 数组的地址可以通过数组名来获取:&intArr
    2. 数组的第一个元素的地址就是数组的首地址
    func main(){
    	var intArr [3]int//int占8个字节 如果是int32就是4个字节
    	//当我们定义完数组后,数组的各个元素有默认值0
    	fmt.Println(intArr)//[0 0 0]
    	fmt.Printf("数组的地址是:%p\n",&intArr)
    	//数组的地址是:0xc0420082c0
        fmt.Printf("数组首地址是:%p,地址intArr[1]的地址是%p",&intArr[0],&intArr[1])
        //数组首地址是:0xc04205c0a0,地址intArr[1]的地址是0xc04205c0a8
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    数组的使用

    访问数组元素

    数组名[下标]比如:你要使用a数组的第三个元素 a[2]

    案例:

    循环输入5个成绩,保存到float64数组,并输出

    func arry(){
    	//从终端输入5个成绩,保存到float64数组,并输出
    	var score[5]float64
    	for i:=0;i<5;i++{
    		fmt.Printf("请输入第%v个元素的值:",i)
    		fmt.Scanln(&score[i])
    	}
    	// fmt.Println("score的值是",score)
    	//遍历数组打印
    	for i :=0;i< len(score);i++{
    		fmt.Printf("score[%v]=%v\n",i,score[i])
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    四种初始化数组的方式:

    func main(){
    
    // 四种初始化数组的方式
    //way1
    var numArr01 [3]int=[3]int{1,2,3}
    fmt.Println("numArr01=",numArr01)
    //输出结果为:numArr= [1 2 3]
    //way2
    var numArr02 =[3]int{5,6,7}
    fmt.Println("numArr02=",numArr02)
    //输出结果为:numArr02= [5 6 7]
    //way3
    var numArr03 =[...]int{8,9,10}
    //这里的[...]是规定的写法
    fmt.Println("numArr03=",numArr03)
    //numArr03= [8 9 10]
    // way4
    var numArr04 =[...]int{1:800,0:900,2:999}
    fmt.Println("numArr04=",numArr04)
    //numArr04= [900 800 999]
     //类型推导   
     numArr05 :=[...]string{1:"tom",0:"jfon",2:"feilipu"}
     fmt.Println("numArr05=",numArr05)
    //numArr05= [jfon tom feilipu]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    数组的遍历

    for -range结构遍历

    这是Go语言一种独有的遍历,可以用来遍历访问数组元素

    基本语法

    for index,value := range array01{
    ...
    }
    
    • 1
    • 2
    • 3

    说明

    • 第一个返回值index是数组的下标
    • 第二个value是在该下标位置的值
    • 他们都是仅在for循环内部可见的局部变量
    • 遍历数组元素的时候,如果不想使用下标index,可以直接把下标index标为下划线
    • index和value的名称不是固定的,即程序员可以自行指定,一般命名为index和value

    案例演示:

    func main(){
    	//演示for -range遍历数组
    	heroes :=[...]string{"刘备","张飞","关羽"}
    	fmt.Println(heroes)
    	//for -range遍历
    	for i,v :=range heroes{
    		fmt.Printf("i=%v,v=%v",i,v)//i=0,v=刘备i=1,v=张飞i=2,v=关羽s
    	//除此之外这样遍历也可以
            fmt.Printf("heroes[%d]=%v\n",i,heroes[i])
        }
        //不要元素的下标只要元素的值可以这样写:
        
        for _,v :=range heroes{
    		fmt.Printf("元素的值=%v\n",v)
    	}
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    数组的注意事项和细节

    1)数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化

    //1)数组是多个相同类型数据的组合,一个数组一旦
    	// 声明/定义了,其长度是固定的,不能动态变化
    	var arr01 [3]int
    	arr01[0] =1
    	arr01[1] =30
    	//arr01[2] =1.1//这里会报错类型不一致
        arr01[2] =90
        // arr01[3] =890//数组会发生越界,超出指定范围长度
    
    	fmt.Println(arr01)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2)var arr []int这时arr是一个slice切片

    数组需要写大小 var arr[3]int这样的写法才是数组

    3)数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用

    4)数据创建后,如果没有赋值,有默认值

    数组类型数组 默认值为0
    字符串数组,默认值""
    bool数组,默认值为false
    
    //数组创建后,如果没有赋值,有默认值(0值)
       //1.数值(整数系列,浮点数系列)=》0
       //2.字符串==》""
       //3.bool类型 ==》flase
      var arr01 [3]float32
      var arr02 [3]string
      var arr03 [3]bool
      fmt.Printf("arr01=%v arr02=%v arr03=%v",arr01,arr02,arr03)
    //输出结果 arr01=[0 0 0] arr02=[  ] arr03=[false false false]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5)使用数组的步骤:1.声明数组并开辟空间 2给数组各个元素赋值 3使用数组

    6)数组的下标是从0开始的

    //数组的下标是从0开始
    var arr04 [3]string //0-2
    fmt.Println(arr04[3])// 报错,原因是数组越界
    
    
    • 1
    • 2
    • 3
    • 4

    7)数组下标必须在指定范围内使用,否则报panic,数组越界比如:var arr[5]int 则下标为0~4

    8)Go的数组属于值类型,在默认情况下不是值传递,因此会进行值拷贝。数组间不会相互影响

    在这里插入图片描述

    //函数
    func test01(arr [3]int){
      arr[0] = 88
      
    }
    main中进行调用
    arr := [3]int{11,22,33}
    test01(arr)
    fmt.Println(arr)//输出结果仍然是:[11 22 33]	无影响
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    9)如想在其它函数中,去修改原来的数组,可以使用引用传递【指针方式】
    在这里插入图片描述

    //函数
    func test02(arr *[3]int){
    	(*arr)[0] = 88
    	
      }
      main中进行调用
      arr := [3]int{11,22,33}
    test02(&arr)
    fmt.Println("main里面的arr的值是",arr)
    //输出的内容是
    // main里面的arr的值是 [88 22 33]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    1 默认值拷贝
    func modify(arr []int){ //编译就直接报错因为没有指定长度
    arr[0] = 100
    fmt.Println("modify的值arr",arr)
    }
    func main(){
    var arr = [...]int{1,2,3}
    modify(arr)
    }2 默认值拷贝
    func modify(arr [4]int){ 
    arr[0] = 100
    fmt.Println("modify的值arr",arr)
    }
    func main(){
    var arr = [...]int{1,2,3}
    modify(arr)
    }2 默认值拷贝
    func modify(arr [4]int){ 
    arr[0] = 100
    fmt.Println("modify的值arr",arr)
    }
    func main(){
    var arr = [...]int{1,2,3}
    modify(arr)
    }
    //编译错误,长度是数据类型的一部分2 默认值拷贝
    func modify(arr [3]int){ 
    arr[0] = 100
    fmt.Println("modify的值arr",arr) 100 2 3
    }
    func main(){
    var arr = [...]int{1,2,3}
    modify(arr) // 1 2 3
    }
    //这个正确,但是不能修改成功
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    数组的应用案例

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

    func th1(){//自己写的
    	//声明一个数组
    	var arr [26]byte
    	arr[0]='A'
    	for i :=1;i<26;i++{
    		arr[i]=arr[i-1]+1
    	}
    	for a,v :=range arr{
    		fmt.Printf("arr[%d]=%c ",a,v)
    	}
    }
    
    func the1(){//老师写的
    	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])
    	}
    }
    func main(){
      //th1()
      the1()
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

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

    //请求出一个数组的最大值,并得到对应的下标
    /*
    1.声明一个数组[6]int{12,56,7,9,23,1}
    2.假定第一个数为最大值,下标就为0
    3,然后从第二个元素开始循环比较,如果发现有更大则交换
    */
    func the2(){
      arr :=[6]int{12,56,7,90,23,1}
      var max int =arr[0]
      maxValIndex :=0
      for i :=1;i<len(arr);i++{
    	if arr[i]>max{
    		max=arr[i]
    		maxValIndex=i
    	}
      }
      fmt.Printf("max=%v,index=%v",max,maxValIndex) 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3)请求出一个数组的和以及他的平均值 。for-range

    //请求出一个数组的和以及平均值。for-range
    func suma(){
    	//1.声明一个数组arr :=[6]int{12,56,7,90,23,1}
    	//2.求出sum
    	//3.求出平均值
    	arr :=[6]int{12,57,7,90,23,1}
    	sum :=0
    	for _,v :=range arr{
    		//累积求和
    		sum += v
    	}
    	fmt.Printf("数组的和是%v,数组的平均值是%.2f",sum,float64(sum)/float64(len(arr)))
    }
    
    
    func main(){
      suma()
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    数组的复杂使用—数组反转

    要求:随机生成5个数,并将其反转打印

    /*
    要求:随机生成5个数,并将其反转打印
    思路
    1.随机生成5个数,rand.Intn()函数
    2,当我们得到随机数后就放到一个数组中 int数组
    3.反转打印
    */
    func fanzhuan(){
    	var intArr3 [5]int
        len :=len(intArr3) //先算出数组的长度,避免反复调用
    	//为了每次生成的随机数都不一样,我们需要给一个seed值
    	rand.Seed(time.Now().UnixNano())
    for i := 0; i < len);i++{
    	intArr3[i] =rand.Intn(100) //0<=n<=100
    }
        
       fmt.Println("交换前:",intArr3)
    //3.反转打印,交换的次数是len/2 2.倒数第一个和第一个交换倒数第二个与第二个进行交换
    
    temp :=0 //作为一个临时变量用于交换操作
    for i := 0; i < len/2;i++{
    	temp =intArr3[len-1 -i] //倒数第n个和第n个元素进行交换
    	intArr3[len-1 -i]=intArr3[i]
    	intArr3[i] = temp
    
    }
    fmt.Println(intArr3)
    
    fmt.Println("交换后:",intArr3)
    
    
    最后main中调用即可
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    4.slice切片

    为什么需要切片?

    先看一个需求:我们需要一个数组用于保存学生的成绩,但是学生的个数是不确定的,请问怎么办,解决方案:使用切片

    1.基本介绍

    1)切片的英文slice

    2)切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制

    3)切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度len(slice)都一样

    4)切片的长度是可以变化的,因此切片是一个可以动态变化数组

    5)切片定义的基本语法

    var 变量名 []类型
    
    • 1

    比如: var a []int

    入门案例

    func main(){
    	//演示切片的基本使用
    	var intArr [5]int = [...]int{1,22,33,66,99}
    	//声明定义一个切片
    	/*
         1.slice 就是切片的名称
    	 2.intArr[1:3] 表示slice 引用到intArr这个数组
    	 3.应用inArr数组的起始下标为1终止下标为3不包含3
    	*/
        slice := intArr[1:3] 
        fmt.Println("intArr=",intArr) // intArr= [1 22 33 66 99]
        fmt.Println("slice 的元素是=",slice)//slice 的元素是= [22 33]
        fmt.Println("slice 的元素的个数是=",len(slice))//slice 的元素的个数是= 2
    	fmt.Println("slice 的容量是=",cap(slice))//slice 的容量是= 4
    	//切片的容量是可以动态变化的 cability
        fmt.Printf("intArr[1]的地址=%p\n",&intArr[1])
    	fmt.Printf("slice[0]的地址=%p slice[0]=%v\n",&slice[0],slice[0])
    	slice[0]=34 //相当于*intArr[1]=34
    	fmt.Println("intArr=",intArr)//intArr= [1 34 33 66 99]
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.切片在内存中的形式

    为了让大家更加深入的理解切片,我们画图分析一下切片在内存中是如何布局的

    在这里插入图片描述

    这是一个非常重要的知识点

    1)以前面的案例来分析切片在内存中的布局

    2)切片底层的数据结构可以理解成一个结构体struct

    3)输出切片和切片的引用地址

    2.切片使用的三种方式
    way1

    第一种方式:定义一个切片,然后让切片去引用一个已经创建好的数组像前面的案例

    func main(){
    	//演示切片的基本使用
    	var intArr [5]int = [...]int{1,22,33,66,99}
    	//声明定义一个切片
    	/*
         1.slice 就是切片的名称
    	 2.intArr[1:3] 表示slice 引用到intArr这个数组
    	 3.应用inArr数组的起始下标为1终止下标为3不包含3
    	*/
        slice := intArr[1:3] 
        fmt.Println("intArr=",intArr) // intArr= [1 22 33 66 99]
        fmt.Println("slice 的元素是=",slice)//slice 的元素是= [22 33]
        fmt.Println("slice 的元素的个数是=",len(slice))//slice 的元素的个数是= 2
    	fmt.Println("slice 的容量是=",cap(slice))//slice 的容量是= 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    way2

    第二种方式:通过make来创建切片

    基本语法:

    var 切片名 []type = make([].len,[cap])
    参数说明:type就是数据类型 len:大小 cap指定切片的容量可选
    
    • 1
    • 2

    案例演示

    func main(){
        var slice []int =make([]int,4,10)
        fmt.Println(slice)//默认值为0
        fmt.Println("slice len=",len(slice),"slice cap=",cap(slice))
        slice[0]=100
        slice[2]=100
        fmt.Println(slice)
        
    }
    
    //演示切片的使用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))
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    内部有个数组是不可见的

    对上面代码的小结:(面试重点)

    1)通过make方式创建切片可以指定切片的大小和容量

    2)如果没有给切片的各个元素赋值,那么就会使用默认值[int,float=>0 string=>" " bool=>false]

    3)通过make方式创建的切片对应的数组是由make底层维护,对外不可见,即只能通过slice方式去访问

    way3

    第3中方式:定义一个切片,直接就指定具体数组,使用原理类似make方式

    	//第3中方式:定义一个切片,直接就指定具体数组,使用原理类似make方式
    
    	var strSlice []string = []string {"tom","jack","mary"}
    	fmt.Println(strSlice)
    	fmt.Println("strSlice的size=",len(strSlice))//3
    	fmt.Println("strSlice的cap=",cap(strSlice))//3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.切片的遍历

    切片的遍历和数组一样,也有两种方式‘

    1)for循环常规遍历方式

    案例演示

    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 ",i,slice[i])//slice[0]=20 slice[1]=30 slice[2]=40
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2)for-range结构遍历切片

    案例演示:

    //使用for -range 方式遍历切片
    	for i,v :=range slice{
    		fmt.Printf("slice[%v]=%v ",i,v)slice[0]=20 slice[1]=30 slice[2]=40
    	}
    
    • 1
    • 2
    • 3
    • 4
    3.切片的注意事项

    1)切片初始化时 var slice = arr[start index:endindex]

    说明:从arr数组下标为startindex,取到下标为endindex的元素(不含 arr[endindex])

    2)切片初始化时,仍然不能越界。范围在[0-len(arr)]之间,但是可以动态增长

    1)var slice = arr[0:end]可以简写 var slice = arr[:end]

    2)var slice = arr[start:len(arr)]可以简写:var slice = arr[start:]

    3)var slice = arr[0:len(arr)]可以简写:var slice = arr[:]

    • cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素

    • 切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组或者make一个空间供切片来使用

    • 切片可以继续切片

          slice2 := slice[1:2] //20
      	fmt.Println("slice1=",slice2) //[20]
      
      • 1
      • 2

      当一个切片元素发生变化,其关联的数组和其他切片也会变化。因为切片是引用数据类型

      3)用append内置函数,可以对切片进行动态追加

      //用append内置函数,可以对切片进行动态追加
      	var slice3 []int = []int{100,200,300}
      	//通过append直接对slice3追加具体的元素
      	slice3 = append(slice3,400,500,600)
      	
      	fmt.Println("slice3=",slice3)
      
      	//通过append将切片slice3追加到slice3
      	slice3 = append(slice3,slice3...)
      	fmt.Println("slice3=",slice3)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    4)切片append操作的底层原理分析

    在这里插入图片描述

    • 切片append操作的本质就是对数组的扩容
    • go底层会创建一个新的数组newArr(安装扩容后的大小)
    • 将slice原来包含的元素拷贝到新的数组newArr
    • slice重新引用到newArr
    • 注意newArr是在底层来维护的,程序员是不可见的
    • 案例演示

    5)切片的拷贝操作

    切片使用copy内置函数完成拷贝

    //切片的拷贝操作
    	//切片的copy内置函数完成拷贝,举例说明
    	var slice4 []int =[]int{1,2,3,4,5}
    	var slice5 = make([]int,10)
    	copy(slice5,slice4)//将slice4拷贝给slice5
    	fmt.Println("slice4=",slice4)//[1 2 3 4 5]
    	fmt.Println("slice5=",slice5)//[1 2 3 4 5 0 0 0 0 0]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (1)说明:copy(para1,para2):para1和para2都是切片类型

    (2)按照上面的代码来看,slice4和slice5的数据空间是独立的,相互不影响,也就是说slice[0]=9999,slice5[0]仍然是1不会受到影响

    思考题

    var a []int =[]int{1,2,3,4,5}
    	var slice5 = make([]int,1)
    	copy(slice5,a)//ok只拷贝一个元素
    fmt.Println(slice5) //[1]
    
    • 1
    • 2
    • 3
    • 4

    上面的代码没有问题

    切片式引用类型,所以在传递时,遵守引用传递机制

    func main(){
    var slice[]int
    var arr[5]int = [...]int{1,2,3,4,5}
    slice = arr[:]
    var slice2 = slice
    slice2[0] =10
    fmt.Println("slice2",slice2) //[10,2,3,4,5]
    fmt.Println("slice",slice)//[10,2,3,4,5]
    fmt.Println("arr",arr) //[10,2,3,4,5]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    func test(slice []int){
    	slice[0]=100
    }
    func main(){
    	var slice = []int{1,2,3,4}
    	fmt.Println("slice=",slice)//[1,2,3,4]
    	test(slice)
    	fmt.Println("slice=",slice)[100,2,3,4]
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    4.string和slice

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

    案例演示:

    func main(){
    	//string底层是一个byte数组,因此string也可以进行切片处理
    	str:= "hello mrliu"
    	//使用切片获取mrliu
    	slice :=str[6:]
    	fmt.Println("slice",slice) //slice=mrliu
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2)string和切片在内存种的形式,”abcd“画出内存示意图

    在这里插入图片描述

    3)string是不可改变的,也就是说不能通过str[0]='z’方式来修改字符串

    	//string底层是一个byte数组,因此string也可以进行切片处理
    	str:= "hello mrliu"
    	//使用切片获取mrliu
    	slice :=str[6:]
    	fmt.Println("slice",slice) //slice=mrliu
     //string是不可改变的,也就是说不能通过str[0]='z'方式来修改字符串
    //  str[0] = 'z' //错误,编译不会通过string是不可变的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4)如果需要修改字符串,可以先将string->[]byte / 或者 []rune ->修改->重写转成string

    //如果需要修改字符串,可以先将string->[]byte / 或者 []rune ->修改->重写转成string
    "hello mrliu"=》改成"zello mrsliu"
     arr1 := []byte(str)
     arr1[0]='z'
     str = string(arr1)
     fmt.Println(str)//zello mrliu
    
    //细节:我们转成[]byte后,可以处理英文和数字,但是没办法处理中文
    //原因是 []byte字节来处理,而一个汉字是3个字节。因此就会出现erro
    //解决办法是将string转成[]rune即可,因为[]rune是按照字符处理兼容汉字
    
    arr1 := []rune(str)
    arr1[0]='北' //utf-8 21271
    str = string(arr1) 
    fmt.Println(str)//北ello mrliu
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.切片的课堂练习

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

    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(){
    	/*
    说明:编写一个函数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.声明一个函数fbn(n int)([]uint64)
    2.编写fbn(n int)进行for循环来存放斐波那契数列
    */
    fnbSlice :=fbn(10)
    fmt.Println(fnbSlice) //[1 1 2 3 5 8 13 21 34 55]
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    5.二维数组

    (2)快速入门案例

    请使用二维数组输出如下图形

    000000
    001000
    020300
    000000
    
    • 1
    • 2
    • 3
    • 4

    使用方式:先声明/定义再赋值

    实现:

    1)语法:

    var 数组名[大小][大小]类型
    var arr [2][3]int,再赋值
    
    • 1
    • 2

    2)代码演示

    /*
    000000
    001000
    020300
    000000
    定义声明一个二维数组
    */
    func demo1(){
    	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()
    	 }	
    }
    func main(){
     demo1()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4)二维数组在内存中的存在形式(重点)

    在这里插入图片描述

    func arrmemory(){
    	var arr2 [2][3]int 
    	arr2 [1][1]=10
    	fmt.Println(arr2)
    
    	fmt.Printf("arr2[0]的地址是%p\n",&arr2[0])
    	//arr2[0]的地址是0xc04207a030 与arr2[1]相差24个字节
    	fmt.Printf("arr2[1]的地址是%p\n",&arr2[1])
    	//arr2[1]的地址是0xc04207a048
    
    	fmt.Printf("arr2[0][0]的地址是%p\n",&arr2[0][0])
    	//arr2[0][0]的地址是0xc04207a030
    	fmt.Printf("arr2[1][0]的地址是%p\n",&arr2[1][0])
    	// arr2[1][0]的地址是0xc04207a048
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (2)使用方式2:直接初始化

    1)声明 :

    var 数组名 [大小][大小]类型 =[大小][大小]类型{{初值..},{初值...}}
    
    • 1

    2)赋值(有默认值,比如 int 类型就是0)

    3)使用演示

    func demo3 (){
    	var arr3 [2][3]int = [2][3]int{{1,2,3},{4,5,6}}
    	fmt.Println("arr3=",arr3)//arr3= [[1 2 3] [4 5 6]]
    }
    
    • 1
    • 2
    • 3
    • 4

    4)说明:二维数组在声明/定义时也应有四种写法【和一维数组类似】

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

    (3)二维数组的遍历

    1)双层for循环完成遍历

    案例:

    func bainli(){
    	//演示二维数组的遍历
    	var arr3 = [2][3]int{{1,2,3},{4,5,6}}
    
    	//for循环来遍历
    	for i :=0;i<len(arr3);i++{
    		for j :=0; j < len(arr3[i]); j++{
    			fmt.Printf("%v\t",arr3[i][j])
    		}
    		fmt.Println()
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2)for-range方式完成遍历

    案例演示:

    // for -range遍历
    	for i,v := range arr3{
    		for j , v2 := range v{
    			fmt.Printf("arr3[%v][%v]=%v\t",i,j,v2)
    
    		}
    		fmt.Println()
    		
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (3)二维数组的应用案例

    定义一个二维数组,用于保存三个班,每个班五名同学成绩,并求出每个班级的平均分、以及所有班级的平均分

    package main
    import (
    	"fmt"
    )
    /*
    定义一个二维数组,用于保存三个班,每个班五名同学成绩,
    并求出每个班级的平均分、以及所有班级的平均分
    */
    func classf(){
    	//定义一个二维数组
    	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)
    
    	//遍历输出成绩后的二维数组,统计平均分
    	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",
    	totalSum,totalSum/15)
    
    
    }
    
    func main(){
    classf()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    1.排序

    1)排序的基本介绍

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

    2)排序的分类:

    (1)内部排序:

    指将需要处理的所有数据都加载到内部存储器中进行排序。

    包括(交换式排序法选择式排序法和****插入排序法

    (2)外部排序法

    数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法直接合并排序法

    3)交换式排序

    交换式排序属于内部排序法,是运用数据值比较后,依判断规则对数据位置进行交换,以达到排序的目的

    交换式排序又分为两种

    1)冒泡排序法(Bubble sort)

    2)快速排序法(Quick sort)

    4)交换式排序法–冒泡排序

    (1)基本思想

    冒泡排序(Bubble sort0)的基本思想是:通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素的排序码,若发现逆序交换,使排序码较小的元素逐渐从后部移向前部(从下标较大的单元移向下标较小的单元),就像水底下的气泡一样逐渐向上冒。

    因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换,从而减少不必要的比较

    (2)案例

    我们将5个数字:24,69,80,57,13使用冒泡排序将其排成一个从小到大的有序数列

    在这里插入图片描述

    package main
    import (
    	"fmt"
    )
    //冒泡排序
    func BubbleSort(arr *[5]int){
    	fmt.Println("排序前的ar=",(*arr))
    	temp :=0//临时变量用来做交换的
    	//完成第一轮排序(外层排序)
    	for j :=0;j < 4;j++{
    		if (*arr)[j] > (*arr)[j+1]{
    			//交换
                temp = (*arr)[j]
    			(*arr)[j]=(*arr)[j+1]
    			(*arr)[j+1] = temp
    		}
    	}
    	fmt.Println("第一次排序过后arr=",(*arr))//[24 69 57 13 80]
    
    	//完成第二轮排序(外层排序)
    	for j :=0;j < 3;j++{
    		if (*arr)[j] > (*arr)[j+1]{
    			//交换
                temp = (*arr)[j]
    			(*arr)[j]=(*arr)[j+1]
    			(*arr)[j+1] = temp
    		}
    	}
    	fmt.Println("第三次排序过后arr=",(*arr))//[24 57 13 69 80]
        //完成第二轮排序(外层排序)
    	for j :=0;j < 2;j++{
    		if (*arr)[j] > (*arr)[j+1]{
    			//交换
                temp = (*arr)[j]
    			(*arr)[j]=(*arr)[j+1]
    			(*arr)[j+1] = temp
    		}
    	}
    	fmt.Println("第三次排序过后arr=",(*arr))//arr= [24 13 57 69 80]
    
    	//完成第四轮排序(外层排序)
    	for j :=0;j < 1;j++{
    		if (*arr)[j] > (*arr)[j+1]{
    			//交换
                temp = (*arr)[j]
    			(*arr)[j]=(*arr)[j+1]
    			(*arr)[j+1] = temp
    		}
    	}
    	fmt.Println("第四次排序过后arr=",(*arr))完成第二轮排序(外层排序)
    	for j :=0;j < 2;j++{
    		if (*arr)[j] > (*arr)[j+1]{
    			//交换
                temp = (*arr)[j]
    			(*arr)[j]=(*arr)[j+1]
    			(*arr)[j+1] = temp
    		}
    	}
    	fmt.Println("第四次排序过后arr=",(*arr))//[13 24 57 69 80]
    
    }
    
    func BubbleSort2(arr *[5]int){
    	fmt.Println("排序前的ar=",(*arr))
    	temp :=0//临时变量用来做交换的
    	len :=len((*arr))
    	//完成第一轮排序(外层排序)
    	for i :=0;i<len-1;i++{
    	for j :=0;j < len-i-1;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 := [5]int{24,69,80,57,13}
    	//将数组传递给一个函数,完成排序
        //BubbleSort(&arr)
        BubbleSort2(&arr) //调用改写之后的冒泡排序
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    2.查找

    1)介绍

    在Golang中,我们常用的查找有两种

    (2) 顺序查找

    (2)二分查找

    2)案例演示

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

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

    package main
    import (
    	"fmt"
    )
    /*
    (1)有一个数列:白眉鹰王、
    金毛狮王、紫衫龙王、青翼斧王
    
    猜数游戏:从键盘任意输入一个名称,
    判断数列中是否包含此名称
    思路:
    1.定义一个数组:白眉鹰王、金毛狮王、紫衫龙王、青翼斧王
    2.从控制台接收一个名词,依次比较如果发现有就提示
    */
    func find1(){
    	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",heroName,i)
    			break
    		} else if i ==(len(names)-1){//判断当i为最后一个下标
    			fmt.Printf("没有找到%v",heroName)
    		}
    	}
    }
    
    //顺序查找第二种方式(推荐)
    func find2(){
    	names := [4]string{"白眉鹰王","金毛狮王","紫衫龙王","青翼斧王"}
    	var heroName = " "
    	fmt.Println("请输入要查找的人名...")
    	fmt.Scanln(&heroName)
    
    	index := -1
    	for i :=0; i < len(names); i++{
    		if heroName == names[i]{
    			index =i
    			break
    		}
    	}
    	if index != -1{
    		fmt.Printf("找到了%v,下标%v",heroName,index)
    	}else{
    		fmt.Printf("没有找到%v",heroName)
    	}
    
    }
    
    func main(){
    	// find1()
    	find2()
      
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    (2)请对一个有序数列进行二分查找{1,8,10,89,1000,1234}.输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示“没有这个数”会使用到递归

    二分法查找的思路分析

    arr = [1,8,10,89,1000,1234] 8
    二分法查找的思路:比如我们要查找的数是findVal
    1.arr是有一个有序数组,并且是从小到大排序
    2.先找到中间的下标middle =(leftindex + rightindex)/2然后让中间的值和findval进行比较
    逻辑:
    2.1如果arr[middle]>findval,就应该问 leftindex----(middle -1)
    2.1如果arr[middle] rightindex
    //找不到
    return ..
    思路---代码
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    func BinaryFind(arr *[6]int,leftindex,rightindex,findVal int){
    	//判断leftIndex是否大于rightindex
    	if leftindex >rightindex{
    		fmt.Println("没有找到")
    		return
    	}
    
    
    	
    	//先找到中间的下标
    	middle :=(leftindex + rightindex) /2
    	if (*arr)[middle] > findVal{
    		//说明我们要查找的数,应该在 leftIndex ---middel-1之间
    		BinaryFind(arr,leftindex,middle -1,findVal)
    	}else if (*arr)[middle] < findVal{
    		//说明我们要查找得数在middel + -----rightindex
    		BinaryFind(arr,middle +1,rightindex,findVal)
    	}else{ //就是当Arr[middle]==findVal的时候
    		//找到了
    		fmt.Printf("找到了下标为%v\n",middle)
    	}
    
    
    }
    
    func main(){
        arr := [6]int{1,8,10,89,1000,1234}
        BinaryFind(&arr,0,len(arr)-1,1000)//找到了下标为4
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    二、map

    1.map的基本介绍

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

    2.map的声明

    基本语法

    var map 变量名 map[keptype]valuetype
    
    • 1

    key可以是什么类型

    golang中的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
    
    • 1
    • 2
    • 3
    • 4

    注意:声明是不会分配内存的,初始化需要make,分配内存后才能赋值和使用

    案例演示:

    func main(){
    	//map的声明和注意事项,map是无序的数据结构
    	var a map[string]string
    	//使用、map前,需要先make,make的作用就是给map分配数据空间
    	a  = make(map[string]string,10) //最大可以放10对
    	a["ao1"]="宋江"
    	a["ao2"]="吴用"
    	a["ao3"]="李逵"
    	a["ao4"]="林冲"
    	a["ao5"]="吴用"
    	a["ao5"]="无名" //会覆盖同key的值
        fmt.Println(a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    对上面代码的说明:

    1)map在使用前一定要make

    2)map的key是不能重复,如果重复了,则以最后这个key-value为准

    3)map的value是可以相同的

    4)map的key-value是无序的

    3.map的使用方式

    1)方式1

    func main(){
    	//map的声明和注意事项,map是无序的数据结构
    	var a map[string]string
    	//使用、map前,需要先make,make的作用就是给map分配数据空间
    	a  = make(map[string]string,10) //最大可以放10对
    	a["ao1"]="宋江"
    	a["ao2"]="吴用"
    	a["ao3"]="李逵"
    	a["ao4"]="林冲"
    	a["ao5"]="吴用"
    	a["ao5"]="无名" //会覆盖同key的值
        fmt.Println(a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2)方式2

    //第二种方式
    	cities := make(map[string]string)
    	cities["no1"] = "北京"
    	cities["no2"] = "天津"
    	cities["no3"] = "上海"
    	fmt.Println(cities)//map[no1:北京 no2:天津 no3:上海]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3)方式3

    //第三种方式
    	heroes := map[string]string{
    		"heroe1" : "宋江",
    		"heroe2" : "林冲",
    	}
    herroes["hertoe3"] = "张顺"
    fmt.Println(heroes)//map[heroe2:林冲 heroe1:宋江 heroes:张顺]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    比如:我们要存放3个学生的信息,每个学生有name,sex,adress信息

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

    代码:

    package main
    import(
    	"fmt"
    )
    func main(){
    	studentsMap := make(map[string]map[string]string) 
    	studentsMap["no1"] = make(map[string]string,3)
    	studentsMap["no1"]["name"] = "tom"
    	studentsMap["no1"]["sex"] = "男"
    	studentsMap["no1"]["adrress"] = "北京"
     //第二个学生
        studentsMap["no2"] = make(map[string]string,3)
    	studentsMap["no2"]["name"] = "jhon"
    	studentsMap["no2"]["sex"] = "男"
    	studentsMap["no2"]["adrress"] = "上海"
    
    	fmt.Println(studentsMap["no1"])
    	fmt.Println(studentsMap["no2"])
    	//打印结果如下
    	/*
        map[sex:男 adrress:北京 name:tom]
        map[name:jhon sex:男 adrress:上海]
    	*/
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4.map的增删改查操作

    1)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)
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    2)map删除

    说明:

    delete(map,“key”),delete是一个内置函数,如果key存在,就删除该key-value.如果key不存在,不操作,但是也不会报错

    func delete

    func delete(m map[Type]Type1,key Type)
    
    • 1

    内建函数delete按照指定的键将元素从个映射中删除,若m为nil或无此元素,delete将不进行操作

    案例演示:

    func main(){
    	cities := make(map[string]string)
    	cities["no1"] = "北京"
    	cities["no2"] = "天津"
    	cities["no3"] = "上海"
    	fmt.Println(cities)
    	//因为no3这个key已经存在,因此下面的这句话就是修改
    	cities["no3"] = "深圳"
        fmt.Println(cities)
        //演示删除
    	delete(cities,"no1")
    	fmt.Println(cities)//map[no2:天津 no3:深圳]没有no1
        //当delete指定的key不存在时,删除不会操作,也不会报错
    	delete(cities,"no5")
    	fmt.Println(cities)map[no2:天津 no3:深圳]
        
        //如果希望一次性删除所有的key
    	//1.遍历啊所有的key,如何逐一删除[遍历]
    	//2.直接make一个新空间
    	cities = make (map[string]string)//效率较高
    	fmt.Println(cities)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    3)map的查找

    案例演示

        cities := make(map[string]string)
    	cities["no1"] = "北京"
    	cities["no2"] = "天津"
    	cities["no3"] = "上海"
    //演示map的查找
    	val, ok := cities["no1"]
    	if ok{
    		fmt.Printf("有no1的key,值为:%v\n",val)
    	}else{
    		fmt.Println("没有no1的key,不存在这个值")
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意:如果cities这个map中存在“no1",那么findRes就会返回true,否则返回false

    4)map的遍历:

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

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

    //使用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)
    
    	}
    	//输出结果如下
    	//k=no1 v=北京k=no2 v=天津k=no3 v=上海
    	
    	//使用for-range遍历比较复杂的map
    	studentsMap := make(map[string]map[string]string) 
    	studentsMap["no1"] = make(map[string]string,3)
    	studentsMap["no1"]["name"] = "tom"
    	studentsMap["no1"]["sex"] = "男"
    	studentsMap["no1"]["adrress"] = "北京"
     //第二个学生
        studentsMap["no2"] = make(map[string]string,3)
    	studentsMap["no2"]["name"] = "jhon"
    	studentsMap["no2"]["sex"] = "男"
    	studentsMap["no2"]["adrress"] = "上海"
     
    	for k1,v1 :=range studentsMap{
            fmt.Println("k1=",k1)
    		for k2,v2 := range v1 {
    			fmt.Printf("\t k2=%v v2 = %v\n",k2,v2)
    		}
    	}
    	/*
        输出结果如下
    	k1= no1
             k2=name v2 = tom
             k2=sex v2 = 男
             k2=adrress v2 = 北京
    k1= no2
             k2=sex v2 = 男
             k2=adrress v2 = 上海
             k2=name v2 = jhon
         
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    map的长度

    func len

    func len(v Type)int
    
    • 1

    内置函数的len返回v的长度,这取决于具体类型:

    数组:v中元素的数量
    数组指针:*v中元素的数量(v为nil时panic)
    切片\映射:v中元素的数量:若v为nil,len(v)为0
    字符串:v中字节的数量
    通道:通道缓存中队列(未读取)元素的数量nil,len(v)即为0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    案例演示

    fmt.Printf("cities有%v 对key-value \n",len(cities)) //3对
    
    • 1

    5.map切片

    基本介绍

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

    案例演示

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

    func main(){
    	//演示map切片的使用
    	//1.声明一个map切片
    	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" : "200",
    	}
    	monsters = append(monsters,newMonster)
    
    	fmt.Println(monsters)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    6.map排序

    基本介绍

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

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

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

    案例演示

    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[10:100 1:13 4:56 8:90]
    
    	//如何按照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)
    
    	//遍历切片,然后按照key来输出map的值
    	for _, k := range keys{
    		fmt.Printf("map[%v]=%v\n",k,map1[k])
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    7.map的使用细节

    1)map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map[案例演示]

    func main() {
    	//map是引用类型,
    	// 遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map
      map1 := make(map[int]int)
      map1[1] = 90
      map1[2] = 88
      map1[10] = 1
      map1[20] = 2
      modify(map1)
      //观察结果如果map1[10]= 900说明map是引用类型
      fmt.Println(map1) //map[10:900 20:2 1:90 2:88]
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

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

    //定义一个学生结构体
    type Stu struct {
    	Name string
    	Age int
    	Address string
    }
    func main() {
    
    //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{"jhon",19,"上海"}
    students["no1"] = stu1
    students["no2"] = stu2
    fmt.Println(students) //map[no1:{tom 18 北京} no2:{jhon 19 上海}]
    
    //遍历各个学生的信息
    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)
    	fmt.Println(" ")
    }
    
    }
    //输出结果如下
    map[no1:{tom 18 北京} no2:{jhon 19 上海}]
    学生的编号是no2
    学生的名字是jhon
    学生的年龄是19
    学生的住址是上海
    
    学生的编号是no1
    学生的名字是tom
    学生的年龄是18
    学生的住址是北京
    
    
    D:\myfile\GO\project\src\go_code\map\mapdetails>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    8.综合练习题:

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

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

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

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

    package main
    import(
    	"fmt"
    )
    func modifyUsers(users map[string]map[string]string,name string){
      //判断users中是否有name
    //   v , ok := users[name]
       if users[name] != nil {
    	    //有这个用户
    		users[name]["pws"] = "8888"
       }else {
    	//没有这个用户
    	users[name] = make(map[string]string,2)
    	users[name]["pws"] = "8888"
    	users[name]["nicname"] = "昵称" + name //示意
       }
    }
    func main(){
    	users :=make(map[string]map[string]string)
    	users["smith"] =make(map[string]string,2)
    	users["smith"]["pwd"] = "999999"
    	users["smith"]["nickname"] = "小花猫"
        modifyUsers(users,"tom")
        modifyUsers(users,"mary")
        modifyUsers(users,"smith")
    
    
    	fmt.Println(users)
    	//输出结果为:map[mary:map[pws:8888 nicname:
    	//昵称mary] smith:map[nickname:小花猫 pws:8888 pwd:999999] tom:map[pws:8888 nicname:昵称tom]]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    ess string
    }
    func main() {

    //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{“jhon”,19,“上海”}
    students[“no1”] = stu1
    students[“no2”] = stu2
    fmt.Println(students) //map[no1:{tom 18 北京} no2:{jhon 19 上海}]

    //遍历各个学生的信息
    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)
    fmt.Println(" ")
    }

    }
    //输出结果如下
    map[no1:{tom 18 北京} no2:{jhon 19 上海}]
    学生的编号是no2
    学生的名字是jhon
    学生的年龄是19
    学生的住址是上海

    学生的编号是no1
    学生的名字是tom
    学生的年龄是18
    学生的住址是北京

    D:\myfile\GO\project\src\go_code\map\mapdetails>

    
    8.综合练习题:
    
    1)使用map[string]map[string]string的map类型
    
    2)key:表示用户名,是唯一的,不可以重复
    
    3)如果某个用户名存在,就将其密码修改"8888",如果不存在就增加这个用户信息,(包括nickname和密码pwd)
    
    4)编写一个函数modifyUser(users map[string]map[string] string,name string)完成上述功能
    
    ```go
    package main
    import(
    	"fmt"
    )
    func modifyUsers(users map[string]map[string]string,name string){
      //判断users中是否有name
    //   v , ok := users[name]
       if users[name] != nil {
    	    //有这个用户
    		users[name]["pws"] = "8888"
       }else {
    	//没有这个用户
    	users[name] = make(map[string]string,2)
    	users[name]["pws"] = "8888"
    	users[name]["nicname"] = "昵称" + name //示意
       }
    }
    func main(){
    	users :=make(map[string]map[string]string)
    	users["smith"] =make(map[string]string,2)
    	users["smith"]["pwd"] = "999999"
    	users["smith"]["nickname"] = "小花猫"
        modifyUsers(users,"tom")
        modifyUsers(users,"mary")
        modifyUsers(users,"smith")
    
    
    	fmt.Println(users)
    	//输出结果为:map[mary:map[pws:8888 nicname:
    	//昵称mary] smith:map[nickname:小花猫 pws:8888 pwd:999999] tom:map[pws:8888 nicname:昵称tom]]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

  • 相关阅读:
    docker 入门教程
    ios 16更新内容来了,快来看看有什么变化吧
    内存卡提示要格式化怎么办?
    开源博客项目Blog .NET Core源码学习(18:App.Hosting项目结构分析-6)
    计算机网络第1章 (概述)
    JavaScript 68 JavaScript Browser BOM 68.7 JavaScript Timing 事件
    基于java+SpringBoot+VUE+Mysql+微信小程序物业管理系统
    【git】超详细使用指令
    深入了解 Java 中的时间信息定义、转换、比较和操作
    【无标题】
  • 原文地址:https://blog.csdn.net/weixin_55418082/article/details/133200224