Go语言复合数据类型有数组、切片与映射(Map)
1、数组:长度固定的序列数组是一个长度固定且元素类型相同的数据序列,其长度是类型的一部分[n]T。
-
1.1 关键特性:
- 长度固定:一旦声明,长度不可改变
- 值类型:赋值或者传参的时候会赋值整个数组,对副本的修改不会影响原数组
- 内存连续:元素在内存中连续存储,访问效率高
- 长度是类型的一部分:[3]int和[5]int是不同的类型
-
1.2 声明与初始化
// 各种初始化方式
var arr1 [3]int // 零值初始化: [0, 0, 0]
arr2 := [3]int{1, 2, 3} // 字面量: [1, 2, 3]
arr3 := [...]int{1, 2, 3, 4} // 编译器推断长度: [1, 2, 3, 4]
arr4 := [5]int{1:10, 3:30} // 索引初始化: [0, 10, 0, 30, 0]
- 1.3 适用场景:
- 明确知道元素数量且不会改变的情况,如一周的天数、物理常量。
- 对内存布局有严格要求的场景(利用其连续内存特性)。
- 作为切片的底层存储
| 处理大数组时需注意性能问题,因为它是值传递。请使用切片或数组指针
2、切片:长度不固定的灵活序列
切片是对底层数组的抽象,提供更灵活、动态的序列视图,类型写为 []T
-
2.1 关键特性:
- 动态长度:长度可变,可自动扩容
- 引用类型:持有对底层数组的引用。多个切片可共享同一底层数组,对一个切片的修改可能影响其他共享底层数组的切片
- 三元结构:包含指向底层数组的指针、长度(
len)和容量(cap)。容量是指切片当前可容纳元素的最大数量
-
2.2 新建与初始化:
// 多种创建切片方式
slice1 := make([]int, 5) // 创建一个长度为5的整型切片
slice2 := []int{1, 2, 3, 4, 5} // 使用字面量创建切片
slice3 := slice2[1:4] // 从已有切片创建新切片
fmt.Println("slice1:", slice1)
fmt.Println("slice2:", slice2)
fmt.Println("slice3:", slice3)
//输出为
//slice1: [0 0 0 0 0]
//slice2: [1 2 3 4 5]
//slice3: [2 3 4]
- 2.3 常用操作:
添加元素 (append) :超出容量会触发扩容,通常容量翻倍或按照百分比增加(不固定)。扩容后切片会指向新的底层数组。
slice1 := make([]int, 5) // 创建一个长度为5的整型切片
// 切片追加元素
slice1 = append(slice1, 6, 7, 8)
fmt.Println("After appending, slice1:", slice1)
当程序运行到第三行之前,可以在debug模式下看见slice1的容量cap是5
当程序运行到第四行的时候,debug模式下看见slice1的容量cap是10,说明容量翻倍了
切割切片:slice[low:high]创建的新切片与原切片共享底层数组,也就是只创建了一个新切片的引用,这个时候对新切片内容的修改,会改变底层数组的数据
复制切片 (copy) :实现切片间的深拷贝
slice1 := []int{1, 2, 3, 4, 5} // 定义并初始化一个整数切片 slice1
slice2 := make([]int, len(slice1)) // 创建一个与 slice1 长度相同的切片 slice2
copy(slice2, slice1) // 使用内置的 copy 函数将 slice1 的内容复制到 slice2
slice1[0] = 100 // 修改 slice1 的第一个元素
fmt.Println("slice1:", slice1) // 输出修改后的 slice1
fmt.Println("slice2:", slice2) // 输出未被修改的 slice2,验证深拷贝效果
//输出结果
//slice1: [100 2 3 4 5]
//slice2: [1 2 3 4 5]
-
2.4 适用场景:
-
绝大多数需要动态集合的场景。
-
函数间传递集合数据
-
3、映射(Map):键值对集合映射是存储键值对的无序集合,类型写为 map[K]V
-
3.1 关键特性:
-
键值对:通过键快速检索值。
-
引用类型:赋值和传参传递引用。
-
无序性:遍历顺序不固定。
-
动态性:可动态添加、删除键值对
-
-
3.2 声明与初始化:
//创建映射
personMap := make(map[string]Person)
//添加元素
personMap["Alice"] = Person{name: "Alice", age: 30}
personMap["Bob"] = Person{name: "Bob", age: 25}
- 3.3 常用操作:(增加/修改、删除、查找)
//增加/修改、删除、查找
personMap["Charlie"] = Person{name: "Charlie", age: 35} // 增加元素
personMap["Alice"] = Person{name: "Alice", age: 31} // 修改元素
delete(personMap, "Bob") // 删除元素
person, exists := personMap["Charlie"] // 查找元素
if exists {
fmt.Println("Found:", person)
} else {
fmt.Println("Charlie not found")
}
//输出为
//Found: {Charlie 35}
-
3.4 适用场景:
-
键值关联数据,如字典、缓存、配置项
-
需要快速通过键查找值的场景
-
4、实践时间
我们做一个投票统计程序
votes := make(map[string]int)
//模拟投票
votes["Alice"] += 1
votes["Bob"] += 1
votes["Alice"] += 1
//输出投票结果
for candidate, count := range votes {
fmt.Printf("%s: %d votes\n", candidate, count)
}
//输出为
//Alice: 2 votes
//Bob: 1 votes
世间没有一蹴而就的成功,每一个小小的坚持,最终都会汇聚成美好人生!