一文了解 Go 的复合数据类型[数组、切片 Slice、Map]
- 前言
- 数组
- 数组的创建方式
- 数组的遍历
- Slice 切片
- 切片的创建方式
- 切片的遍历
- 向切片追加元素
- Map
- Map 的创建方式
- Map 的基本操作
- 插入和修改
- 删除
- 查找操作
- 遍历操作
- 删除操作
- 小结
耐心和持久胜过激烈和狂热。
前言
上一篇文章一文熟悉 Go 的基础语法和基本数据类型
,讲解了 Go 的基础语法和基本数据类型,本篇文章将对 Go 的复合数据类型(数组、切片 Slice、Map)进行介绍。
数组
数组是由特定元素组成的固定长度的序列,元素可以是Go 的原生类型(如整形、字符串型和浮点型等)和自定义类型。一个数组可以包含零个或多个元素。通过数组的下标索引可以高效访问和修改每个元素的值,索引从 0 开始,到数组长度 - 1 结束。
数组的创建方式
- 第一种
通过隐式的方式初始化一个长度为 5 的import "fmt" func main() { var arr [5]int fmt.Printf("%d, %d, %d, %d, %d\n", arr[0], arr[1], arr[2], arr[3], arr[4]) //0, 0, 0, 0, 0 arr[0] = 1 fmt.Println(arr[0]) // 1 }int类型数组,数组下标索引从 0 开始,上面输出的值为0, 0, 0, 0, 0,如果初始化数组的时候,不带初始值,那么默认情况下,数组里的每个元素都会被初始化为对应数据类型的默认值,int类型的默认值为0。通过下标索引可以直接访问元素的值和修改元素的值。 - 第二种
显式初始化数组时,可以使用数组字面值语法初始化一个元素或多个元素。import "fmt" func main() { var arr [5]int = [5]int{1} var arr2 = [5]int{1, 2, 3, 4, 5} fmt.Println(arr) // [1 0 0 0 0] fmt.Println(arr2) // [1 2 3 4 5] } - 第三种
初始化数组时,如果长度的位置出现import "fmt" func main() { var arr = [...]int{1, 2, 3, 4} fmt.Println(arr) // [1 2 3 4] fmt.Printf("%T\n", arr) // [4]int }...而不是数字,则表示数组的长度是根据初始值元素的个数去计算的。 - 第四种
初始化数组时,通过import "fmt" func main() { var arr = [...]int{5: 5} fmt.Println(arr) // [0 0 0 0 0 5] }index: value的形式对某个位置的元素进行初始化,其他位置的元素为默认值。
数组的遍历
- 普通 for 循环
输出结果:import "fmt" func main() { var arr = [5]int{1, 2, 3, 4, 5} for i := 0; i < len(arr); i++ { fmt.Printf("索引:%d, 值:%d\n", i, arr[i]) } }索引:0, 值:1 索引:1, 值:2 索引:2, 值:3 索引:3, 值:4 索引:4, 值:5 - for-range 循环
import "fmt" func main() { var arr = [5]int{1, 2, 3, 4, 5} for index, value := range arr { fmt.Printf("索引:%d, 值:%d\n", index, value) } }index为数组的下标索引,value为元素值。
输出结果:索引:0, 值:1 索引:1, 值:2 索引:2, 值:3 索引:3, 值:4 索引:4, 值:5
Slice 切片
- 切片和数组长得很像,但它们各有各的特点。由于数组的长度是固定的这个限制,在使用 Go 的过程中很少直接使用数组,而是使用切片
slice,它是一个动态的序列,程序运行时可以对它动态添加元素。 - 切片的数据结构如下所示
我们可以看到,切片包含三个字段:type slice struct { array unsafe.Pointer len int cap int }array: 指向底层数组的指针;len: 切片的长度,即切片中当前元素的个数;cap: 底层数组的长度,也是切片的最大容量,cap的值永远大于等于len的值。
切片的创建方式
- 声明切片
以上的创建方式只是声明切片,并未初始化,import "fmt" func main() { var arr []int fmt.Printf("长度:%d\n", len(arr)) fmt.Printf("容量:%d\n", cap(arr)) fmt.Println(arr) }arr的值为nil。 - 声明切片并初始化
import "fmt" func main() { var arr = []int{1, 2, 3, 4, 5} fmt.Printf("长度:%d\n", len(arr)) // 5 fmt.Printf("容量:%d\n", cap(arr)) // 5 fmt.Println(arr) // [1 2 3 4 5] } - 通过
make函数来创建切片
通过import "fmt" func main() { /* 第一个参数 -> type 切片的类型 第二个参数 -> len 切片的长度 第三个参数 -> cap 切片的容量 */ arr := make([]int, 2, 5) fmt.Printf("长度:%d\n", len(arr)) // 2 fmt.Printf("容量:%d\n", cap(arr)) // 5 /* 第一个参数 -> type 切片的类型 第二个参数 -> len & cap 切片的长度和容量 */ arr2 := make([]int, 5) fmt.Printf("长度:%d\n", len(arr2)) // 5 fmt.Printf("容量:%d\n", cap(arr2)) // 5 }make函数创建切片时,使用make([]int, 2, 5)的形式,指定了切片的长度为 2,容量为 5;如果使用make([]int, 5)这种形式,不指定容量,那么容量就等于切片的长度。 - 基于存在的数组创建切片
采用import "fmt" func main() { arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} sl := arr[2:4] fmt.Println(sl) // [3 4] }array[low : high]语法基于一个已存在的数组创建切片,这种方式被称为数组的切片化。直接修改sl的元素值会影响arr的元素值,因为sl的底层数组是指向arr的。
切片的遍历
- 普通 for 循环
输出结果:import "fmt" func main() { var arr = []int{1, 2, 3, 4, 5} for i := 0; i < len(arr); i++ { fmt.Printf("索引:%d, 值:%d\n", i, arr[i]) } }索引:0, 值:1 索引:1, 值:2 索引:2, 值:3 索引:3, 值:4 索引:4, 值:5 - for-range 循环
import "fmt" func main() { var arr = []int{1, 2, 3, 4, 5} for index, value := range arr { fmt.Printf("索引:%d, 值:%d\n", index, value) } }index为数组的下标索引,value为元素值。
输出结果:索引:0, 值:1 索引:1, 值:2 索引:2, 值:3 索引:3, 值:4 索引:4, 值:5
向切片追加元素
使用 append 函数可以想切片追加元素
import "fmt"
func main() {
var arr = []int{1, 2, 3, 4, 5}
fmt.Println(arr) // [1 2 3 4 5]
arr = append(arr, 6)
fmt.Println(arr) // [1 2 3 4 5 6]
}
追加的元素被放置在切片的尾部
Map

Map表示的是一组无序的键值对(key → value),在 Go 中的形式为map[key_type]value_type。key和value可以是同一种类型map[int]int,也可以不是同一种类型map[string]int。map中对value的类型没有限制,但是对key却有限制,想要作为map的key,必须满足以下条件:- key 的类型必须支持
==和!=比较操作符
例如int类型的a和b两个变量,是支持a == b和a != b操作的,而Go语言中Slice、map、function复合类型,是不支持T == T和T != T操作的,只支持T == nil的判空操作。
- key 的类型必须支持
Map 的创建方式
- 错误的创建方式
只声明而未初始化,直接使用func main() { var m map[string]string m["name"] = "chenmingyong" }m则会报错m为nil。 - 使用复合字面值初始化
map类型变量import "fmt" func main() { m := map[string]string{} m["name"] = "chenmingyong" fmt.Println(m["name"]) // chenmingyong } - 使用复合字面值显式初始化
map类型变量import "fmt" func main() { m := map[string]string{ "name": "chenmingyong", } fmt.Println(m["name"]) // chenmingyong } - 使用
make创建map类型变量
如果不指定func main() { m1 := make(map[string]string) // 不指定容量,默认会给一个初始值 m2 := make(map[string]string, 5) // 指定容量为 5 }map的容量,默认会给一个初始值。
Map 的基本操作
插入和修改
func main() {
m := make(map[string]string)
// 新增键值对
m["name"] = "chenmingyong"
fmt.Println(m["name"]) // chenmingyong
// 修改 value
m["name"] = "cmy"
fmt.Println(m["name"]) // cmy
}
通过 m[key] = value 的形式对 map 进行插入和修改操作。
删除
import "fmt"
func main() {
m := make(map[string]string)
// 新增键值对
m["name"] = "chenmingyong"
fmt.Println(m["name"]) // chenmingyong
delete(m, "name")
fmt.Println(m["name"]) // ""
}
通过 delete(map, key) 方法,对 map 里面的键值对进行删除。
查找操作
import "fmt"
func main() {
m := make(map[string]string)
m["name"] = "chenmingyong"
value, ok := m["name"]
fmt.Println(ok, value) // true chenmingyong
value2, ok2 := m["age"]
fmt.Println(ok2, value2) // false
}
使用 comma ok 惯用法对 map 进行键查找和键值读取操作,第一个变量接收 value 的值,第二个变量用于判断 key 是否存在,类型为 bool,若 key 不存在,value 的值为对应 key 类型的默认值。
遍历操作
import "fmt"
func main() {
m := make(map[string]string)
m["name"] = "chenmingyong"
m["addr"] = "china"
for key, value := range m {
fmt.Println(key, value)
}
}
通过 for-range 的方式遍历,map 也仅仅支持这种方式的遍历。
删除操作
- 1、通过遍历,逐个删除
import "fmt" func main() { m := make(map[string]string) m["name"] = "chenmingyong" m["addr"] = "china" for key, _ := range m { delete(m, key) } fmt.Println(len(m)) // 0 } - 2、将
map变量指向一个新的map,旧的map将会被gc回收func main() { m := make(map[string]string) m["name"] = "chenmingyong" m["addr"] = "china" m = make(map[string]string) fmt.Println(len(m)) // 0 }
小结
本文对数组、Slice 切片和 Map 的定义和相关操作进行了介绍,后续文章会对 Slice 切片和 Map 的底层原理进行详细介绍。
如果本文对你有帮助,欢迎点赞收藏加关注,如果本文有错误的地方,欢迎指出!




![[附源码]java毕业设计医院仪器设备管理系统](https://img-blog.csdnimg.cn/6ac8cbcc63574e98800ef1e89fe95df1.png)














