当前位置:   article > 正文

go学习之数组与Map_go map 数组

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]<findval,就应该问 middel+1----right
2.3如果Arr[middle]==findVal就找到
对上面的逻辑进行递归执行

递归退出条件
if lefetindex > 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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/206328
推荐阅读
相关标签
  

闽ICP备14008679号