GO语言基础入门-数组切片map的使用 | 青训营笔记

82 阅读7分钟

前言

这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天,其实第五届青训营已经正式开课n多天了,笔记不断更新中,都是我听完课之后的总结和平时自己的学习积累,分享出来给有需要的朋友。

本文内容

本文将涉及到Go语言数组、切片以及map的详细使用和细节讲解。

Go语言基础

1.Go语言数组

(1)创建数组

第一种方式

var numArray01 [3]int = [3]int{1, 2, 3}
fmt.Printf("numArray01=%v\n", numArray01)

第二种方式

var numArray02 = [3]int{4, 5, 6}
fmt.Printf("numArray02=%v\n", numArray02)

第三种方式

var numArray03 = [...]int{7, 8, 9}
fmt.Printf("numArray03=%v\n", numArray03)

注意:默认不写长度 注意如果写成[] 这不是数组,是切片

第四种方式

var numArray04 = [...]int{1: 200, 0: 100, 2: 300}
fmt.Printf("numArray04=%v\n", numArray04)
(2) 数组的遍历

一维数组的遍历

for i, v := range strArray02 {
    fmt.Println(i, v)
}
//如果只需要值不需要下标,可以用_占位符
for _, v := range strArray02 {
    fmt.Println(v)
}

二维数组的遍历

//使用for循环遍历
var arr1 = [2][3]int{{1, 2, 3}, {4, 5, 6}}
​
for i := 0; i < len(arr1); i++ {
    for j := 0; j < len(arr1[i]); j++ {
        fmt.Printf("%v\t", arr1[i][j])
    }
    fmt.Println()
}
fmt.Println()
​
//使用for range来遍历
for _, v := range arr1 {
    for _, v2 := range v {
        fmt.Printf("%v\t", v2)
    }
    fmt.Println()
}
(3)练习案例

案例1:从终端循环输入5个成绩,保存到float64数组,并输出

var score [5]float64
for i := 0; i < 5; i++ {
    fmt.Printf("请输入第%d个元素的值\n", i+1)
    fmt.Scanln(&score[i])
}
for i := 0; i < len(score); i++ {
    fmt.Printf("score[%d]=%v\n", i, score[i])
}

案例2:声明一个数组byte类型数组

使用for循环,利用字符可以进行运算的特点来赋值 'A'+1 ->'B'

var mychars [26]byte
for i := 0; i < 26; i++ {
    mychars[i] = 'A' + byte(i) //注意 需要将i转为byte类型
}
for i := 0; i < len(mychars); i++ {
    fmt.Printf("%c", mychars[i]) //必须格式化一下以字符c输出,否则都是ascii码输出
}

案例3:随机生成五个数,将其反转打印

//为了每次生成的随机数不一样,我们还需要给一个seed种子
rand.Seed(time.Now().UnixNano()) //用纳秒级别更随机
var intArr [5]int
for i := 0; i < len(intArr); i++ {
    intArr[i] = rand.Intn(100)
}
fmt.Println(intArr)
2.Go语言切片
(1)和数组的区别

数组长度不可变化,且是值拷贝/传递,而切片的长度可以改变,并且是引用传递(一个地方修改,其他地方都修改),切片是一个结构体。

(2)创建切片

第一种方式:定义一个切片,然后让切片去引用一个已经创建好的数组,数组是程序员可见的

var myArray [5]int = [...]int{1, 2, 3, 4, 5}
var mySlice = myArray[1:3] //取头不取尾
fmt.Println("切片:", mySlice)

第二种方式:使用make创建切片,也会创建一个数组,但这个数组程序员是不可见的,是底层维护的且没有名字

用法:make([]类型,长度,容量) 容量可以默认不写

//会分配一个长度为5,容量为5的切片,容量可不写默认等于长度
var mySlice2 = make([]int, 5, 5) //初始值为0
mySlice2[0] = 1
fmt.Println("切片2:", mySlice2)
fmt.Printf("切片2的长度:%v,容量:%v\n", len(mySlice2), cap(mySlice2))

通过make创建的切片,是通过底层make维护的,对外不可见,相当于创建一个局部数组,只能通过slice进行访问数据。

第三种方式:定义一个切片,直接指定具体数组,使用原料类型make的方式

var strSlice []string = []string{"tom", "jack", "mary"}
fmt.Println("切片2:", strSlice)
fmt.Printf("切片2的长度:%v,容量:%v\n", len(strSlice), cap(strSlice))
(3)对切片进行追加

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

var slice3 []int = []int{100, 200, 300}
//通过append直接给slice3追加具体元素
slice3 = append(slice3, 400, 500, 600) 
fmt.Println("切片3:", slice3)
fmt.Printf("切片3的长度:%v,容量:%v\n", len(slice3), cap(slice3))

注意,append追加相当于是创建了一个新的数组,需要将值赋给原变量。如果append切片原设定容量足够的话,那么 append(slice3,100)地址是一样的

var slice6 []int
slice6 = make([]int, 5, 6)
fmt.Printf("slice6为%v的地址%p\n", slice6, &slice6)
fmt.Printf("slice6为%v的地址%p\n", append(slice6, 400), append(slice6, 400))
fmt.Printf("slice6为%v的地址%p\n", slice6, &slice6)

但是无论是否超过容量,你都得把值重新赋值给原变量,不然即使修改同地址,但原切片还是没变化。

(4)切片的拷贝操作

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

var slice4 []int = []int{1, 2, 3}
var slice5 = make([]int, 6)
copy(slice5, slice4)           //将slice4拷贝给slice5
fmt.Println("slice4=", slice4) //1,2,3
fmt.Println("slice5=", slice5) //1,2,3,0,0,0
3.Go语言map用法
(1)map基本介绍

map是key-value数据结构,又称字段或者关联数组。类型其他编程语言的集合或者是字典,map是引用传递,调用时如有被修改,则原值也会变化。

(2)map的声明

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

var map 变量名 map[keytype]valuetype 多维map :var map[string]map[string]string 通常key为int,string,slice、map和function不可以当做key

(1)在使用map前,需要先make,作用是给map分配内存空间

var a map[string]string
a = make(map[string]string, 10)
a["name"] = "小王" //key不能重复,如果重复赋值,则覆盖
fmt.Println(a)   //map是无序的

(2)也可以声明的时候直接就make

var mymap = make(map[string]string)
mymap["name"] = "小明" //key不能重复,如果重复赋值,则覆盖
fmt.Println(mymap)   //map是无序的

(3)声明 直接赋值

var mymap3 map[string]string = map[string]string{
    "name": "小红",
}
fmt.Println(mymap3) //map是无序的

(4)案例

存放2个学生信息,每个学生信息有name、sex和age信息

stuMap := make(map[string]map[string]string)
stuMap["stu01"] = make(map[string]string, 3)
stuMap["stu01"]["name"] = "小李"
stuMap["stu01"]["sex"] = "男"
stuMap["stu01"]["age"] = "20"
stuMap["stu02"] = make(map[string]string, 3) //注意这不能少
stuMap["stu02"]["name"] = "小丽"
stuMap["stu02"]["sex"] = "女"
stuMap["stu02"]["age"] = "18"
fmt.Println(stuMap)
fmt.Println(stuMap["stu01"])
fmt.Println("学生1姓名", stuMap["stu01"]["name"])

查找操作

val, ok := stuMap["stu01"]
if ok {
    fmt.Printf("有stu01,key值%v\n", val)
} else {
    fmt.Println("没有stu01 key")
}

修改操作

stuMap["stu01"]["name"] = "小张" //map是无序的,修改后顺序会改变
fmt.Println("学生1姓名修改后:", stuMap["stu01"]["name"])

map循环读取操作

for k1, v1 := range stuMap {
    for k2, v2 := range v1 {
        fmt.Printf("map[%v][%v]值为:%v\n", k1, k2, v2)
    }
}

map删除操作

delete(stuMap, "stu02")
fmt.Println("删除stu02:", stuMap)
//当delete指定的可以不存在时,删除不会操作,也不会报错
delete(stuMap, "stu02")
fmt.Println("删除stu02:", stuMap)

如果希望一次性删除所有key,两个方法

  • 遍历所有的key,然后逐一删除
  • 直接make一个空间
stuMap = make(map[string]map[string]string)
fmt.Println("全部删除:", stuMap)
(3)map切片
var monsters []map[string]string
monsters = make([]map[string]string, 1) //准备放入两个妖怪
newMonster := map[string]string{
    "name": "牛魔王",
    "age":  "200",
}
monsters = append(monsters, newMonster)
fmt.Println(monsters)
fmt.Println(monsters[1])
fmt.Println(monsters[1]["name"])
(4)map结构体类型

map的value也经常使用struct类型,用struct类型更适合管理复杂的数据,比前面value是一个map更好

比如value为struct结构体,下面是实例:

1.map的key是学生的学号,是唯一的

2.map的value为结构体,包含学生的名字,年龄,地址

//定义一个学生结构体
type Stu struct {
    Name    string
    Age     int
    Address string
}
students := make(map[string]Stu, 10)
//创建两个学生信息
stu1 := Stu{"tom", 10, "福建"}
stu2 := Stu{"tom", 20, "广州"}
students["no1"] = stu1
students["no2"] = stu2
​
fmt.Println(students)
for k, v := range students {
​
    fmt.Printf("学生的编号是%v\n", k)
    fmt.Printf("学生的名字是%v\n", v.Name)
    fmt.Printf("学生的年龄是%v\n", v.Age)
    fmt.Printf("学生的地址是%v\n", v.Address)
    fmt.Println()
}
(5)map排序

因为map是无序的,如果我们需要按照map的key的顺序进行排序

思路:

1.先将map的key放入到切片中

2.对切片排序

3.遍历切片,然后按照key来输出map的值

map1 := make(map[int]int, 10)
map1[10] = 100
map1[1] = 13
map1[4] = 56
map1[8] = 90var keys []int
for k, _ := range map1 {
    keys = append(keys, k)
}
//排序
sort.Ints(keys) //先排序key
fmt.Println(keys)
​
for _, k := range keys {
    fmt.Printf("map1[%v]=%v\n", k, map1[k]) //根据key排序
}

总结

要注意数组、切片和map之间的区别。其中数组长度不可变化,而切片和map长度可变,数组是值拷贝,而切片和map是引用传递,调用时如有被修改,则原值也会变化。

写在最后

本文是我的日常学习笔记,如果哪里有写错,麻烦请指出来,感谢。这里我也推荐大家多写笔记,写笔记是一个很好的习惯,可以帮助我们更好的吸收和理解学习的新知识,新的一年大家一起加油!