go学习之数组与Map

news2024/12/28 2:25:02

文章目录

    • 一、数组
      • 1.为什么需要数组
      • 2.数组快速入门
      • 3、数组的定义和内存布局
        • 数组的使用
        • 数组的遍历
        • 数组的注意事项和细节
        • 数组的应用案例
      • 4.slice切片
        • 1.基本介绍
        • 2.切片使用的三种方式
          • way1
          • way2
          • way3
        • 3.切片的注意事项
        • 4.string和slice
      • 5.二维数组
      • 1.排序
        • 1)排序的基本介绍
        • 2)排序的分类:
        • 3)交换式排序
        • 4)交换式排序法--冒泡排序
      • 2.查找
    • 二、map
      • 1.map的基本介绍
      • 2.map的声明
      • 3.map的使用方式
      • 4.map的增删改查操作
        • 1)map增加和更新
        • 2)map删除
        • 3)map的查找
      • 5.map切片
      • 6.map排序
      • 7.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、数组的定义和内存布局

数组的定义

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

数组内存(重要)

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

}
数组的使用

访问数组元素

数组名[下标]比如:你要使用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])
	}
}

四种初始化数组的方式:

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]
}
数组的遍历

for -range结构遍历

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

基本语法

for index,value := range array01{
...
}

说明

  • 第一个返回值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)数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化

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

	fmt.Println(arr01)

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]

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

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

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

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]	无影响

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]

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)创建一个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()

}

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

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

}

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

要求:随机生成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中调用即可

4.slice切片

为什么需要切片?

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

1.基本介绍

1)切片的英文slice

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

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

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

5)切片定义的基本语法

var 变量名 []类型

比如: 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]
}

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
way2

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

基本语法:

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

案例演示

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)通过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

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
	}

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

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

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

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)说明: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]

上面的代码没有问题

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

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

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是不可变的

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

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]

}

5.二维数组

(2)快速入门案例

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

000000
001000
020300
000000

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

实现:

1)语法:

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

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

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
    
}

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

1)声明 :

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

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

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

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

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

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

(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.排序

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) //调用改写之后的冒泡排序

}

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

(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 ..
思路---代码
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
}

二、map

1.map的基本介绍

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

2.map的声明

基本语法

var map 变量名 map[keptype]valuetype

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

注意:声明是不会分配内存的,初始化需要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)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)
}

2)方式2

//第二种方式
	cities := make(map[string]string)
	cities["no1"] = "北京"
	cities["no2"] = "天津"
	cities["no3"] = "上海"
	fmt.Println(cities)//map[no1:北京 no2:天津 no3:上海]

3)方式3

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

练习:演示一个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:上海]
	*/
}

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)


}
2)map删除

说明:

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

func delete

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

内建函数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)
}
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,不存在这个值")
	}

注意:如果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
     

map的长度

func len

func len(v Type)int

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

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

案例演示

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

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

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

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]

}

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>

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1034766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uni-app实现获取未来七天时间和星期几功能

例子如下&#xff1a; HTML&#xff1a; <viewstyle"margin-top: 3%;width: 100%;height: 10vh;display: flex;justify-content: space-around;"><div v-for"(item,index) in same_week" :class"[same_dayitem.date? activ :,dis]"cl…

在虚拟机上安装win10/ubuntu的教程

以下内容源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 一、下载软件资源 1、首先下载虚拟机Vmware_Pro17软件并正确安装&#xff1a;网盘链接 2、然后下载操作系统的镜像文件&#xff1a;MSDN, 我告诉你 - 做一个安静的工具站 二、在虚拟机上安装ubuntu系统 1…

EXP武器库编写

文章目录 pocsuite3工具SQL注入EXP布尔盲注优化最终优化 延时注入 phpstudy2016-2018-RCE利用DVWA文件上传metinfo_5.0.4EXPSQL-布尔盲注文件包含漏洞 定制SQLmaptamper脚本sqli-labs/less-26关卡分析 tamper脚本编写 python是黑客最喜欢的编程语言之一&#xff0c;但同时go语言…

基于AVR128单片机智能电风扇控制系统

一、系统方案 模拟的电风扇的工作状态有3种&#xff1a;自然风、常风及睡眠风。使用三个按键S1-S3设置自然风、常风及睡眠风。 再使用两个按键S4和S5&#xff0c;S4用于定时电风扇定时时间长短的设置&#xff0c;每按一次S4键&#xff0c;定时时间增加10秒&#xff0c;最长60秒…

C/C++程序员技术发展方向(强烈推荐!!)

大家好&#xff0c;我是阿Q。 今天这篇就是专门给现在还迷茫不知道自己到底要做什么方向C开发的同学们。 几年后回过头看的时候&#xff0c;你一定会感谢当初那个努力的自己&#xff01; C作为当下也非常流行的一个面向对象语言&#xff0c;有着非常多的应用&#xff0c;一定…

RHCSA 文件的上传下载(Linux-Windows)

目录 一、SCP 上传&#xff08;Windows--->Linux&#xff09;&#xff1a; 下载&#xff08;Linux--->Windows&#xff09;&#xff1a; 二、STFP 三、XFTP工具 一、SCP 上传&#xff08;Windows--->Linux&#xff09;&#xff1a; 在Windows本地端命令窗口中转…

基因组注释(Annotation)

基因组组装完成后&#xff0c;或者是完成了草图&#xff0c;就不可避免遇到一个问题&#xff0c;需要对基因组序列进行注释。注释之前首先得构建基因模型&#xff0c;有三种策略&#xff1a; 从头注释(de novo prediction)&#xff1a;通过已有的概率模型来预测基因结构&#…

【刷题】2023年第十四届蓝桥杯大赛软件类省赛C/C++大学A组真题

蓝桥杯2023年第十四届省赛真题-平方差 - C语言网 (dotcpp.com) 初步想法&#xff0c;x y2 − z2&#xff08;yz)(y-z) 即xa*b&#xff0c;ayz&#xff0c;by-z 2yab 即ab是2的倍数就好了。 即x存在两个因数之和为偶数就能满足条件。 但时间是&#xff08;r-l&#xff09;*x&am…

C语言回调函数与注册函数的使用

概述 在项目中&#xff0c;经常见到此写法&#xff0c;在此写个demo&#xff0c;方便其他工程师参阅。 开发环境&#xff1a;Visual Studio Community 2022 1、代码 #include <stdio.h>//封装库代码 typedef struct {bool status;void (*setStatus)(int status); }T_…

动手吧,vue单选框

单选框到处可见&#xff0c;组件库不方便自定义样式&#xff0c;还是自己写吧。 效果图&#xff1a; 1、template部分 <template><labelclass"v-radio flex":class"[{ disable: disabled }]":aria-disabled"disabled"><spancla…

如何搭建专属的物联网私有云?需要考虑哪些因素?

随着物联网技术的快速发展&#xff0c;越来越多的企业开始意识到搭建专属的物联网私有云的重要性。私有云是指企业自主建设和管理的云服务环境&#xff0c;其中企业可以实现对数据和服务的全面控制&#xff0c;同时也可以享受云服务的高效性和灵活性。 一、企业做专属物联网私…

基于jenkins+k8s实现devops

1、背景 由于jenkins运行在k8s上能够更好的利用动态agent进行构建。所以写了个部署教程&#xff0c;亲测无坑 2、部署 1、创建ns kubectl create namespace devops 2、kubectl apply -f jenkins.yml apiVersion: v1 kind: ServiceAccount metadata:name: jenkinsnamespace…

用于图像分类的预训练模型(PyTorch实现)

用于图像分类的预训练模型&#xff08;PyTorch实现&#xff09; 在本文中&#xff0c;我们将介绍一些使用 TorchVision 模块中存在的预训练网络的实践示例——用于图像分类的预训练模型。 1. 基于预训练模型进行图像分类 预训练模型是在 ImageNet 等大型基准数据集上训练的神…

力扣刷题-链表-移除链表元素

203.移除链表元素 题意&#xff1a;删除链表中等于给定值 val 的所有节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1a; 输入&#xff1a;head [], val 1 输出&#xff1a;[] 示例 3&#xff1a; 输…

arduino u8g2 表情字库制作

U8G2 下载原代码 &#xff1a; GitHub - olikraus/u8g2: U8glib library for monochrome displays, version 2 1.制作图片 使用FLASH 或任何可以画图的软件制作动态图片PNG格式 大小最好先设定好如40x80 ,最好不要太大 128X64,60X60 将制作好的图片放入 下载好的 u8g2-master…

【每日一题】1539. 第 k 个缺失的正整数

1539. 第 k 个缺失的正整数 - 力扣&#xff08;LeetCode&#xff09; 给你一个 严格升序排列 的正整数数组 arr 和一个整数 k 。 请你找到这个数组里第 k 个缺失的正整数。 示例 1&#xff1a; 输入&#xff1a;arr [2,3,4,7,11], k 5 输出&#xff1a;9 解释&#xff1a;缺失…

国科大体系结构习题 | 第二章 计算机系统结构基础

第二章 习题汇总 Q1. 在3台不同指令系统的计算机上运行同一程序P时&#xff0c;A机需要执行 1.0 1 0 8 1.010^8 1.0108条指令&#xff0c;B机需要执行 2.0 1 0 8 2.0 10^8 2.0108条指令&#xff0c;C机需要执行 4.0 1 0 8 4.010^8 4.0108条指令&#xff0c;但实际执行时间…

Linux 操作技巧

目录 一、shell-命令解释器 二、Linux中的特殊符号 三、命令历史--history 一、shell-命令解释器 shell——壳&#xff0c;命令解释器&#xff0c;负责解析用户输入的命令 ——内置命令&#xff08;shell内置&#xff09; ——外置命令&#xff0c;在文件系统的某个目录下&…

Redis Insight 版本 2.32 翻译中文

使用教程 链接&#xff1a;https://pan.baidu.com/s/11pWBZ3uQSRZbuMS8POkLCw?pwd2ke5 一、下载renderer.js 1.打开安装好的软件 2、在这里添加我们指定的文件夹&#xff0c;这个文件夹是你随便创建的&#xff0c;你可以指定任何目录 3.选择renderer.js右键保存覆盖 4.在r…

Flask数据库之SQLAlchemy--介绍--链接数据库

目录 SQLAlchemy介绍 SQLAlchemy连接数据库 SQLAlchemy介绍 数据库是一个网站的基础&#xff01;&#xff01;&#xff01; 比如MySQL、MongoDB、SQLite、PostgreSQL等&#xff0c;这里我们以MySQL为例进行讲解。 SQLAlchemy是一个ORM框架 对象关系映射&#xff08;英语&…