141 lines
4.1 KiB
Markdown
141 lines
4.1 KiB
Markdown
|
|
---
|
|||
|
|
tags:
|
|||
|
|
- Go
|
|||
|
|
- golang
|
|||
|
|
- go基础语法
|
|||
|
|
- 数组
|
|||
|
|
- 切片
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Go语言数组与切片
|
|||
|
|
|
|||
|
|
在Go语言中,数组和切片是两种重要的数据结构,它们看起来很相似,但使用场景和特点却大不相同。今天就让我们通过一些生动的例子,深入理解这两个概念。
|
|||
|
|
|
|||
|
|
## 数组:固定长度的"储物柜"
|
|||
|
|
|
|||
|
|
### 什么是数组?
|
|||
|
|
想象一下,数组就像一个固定大小的储物柜,有着明确数量的格子,每个格子只能存放相同类型的物品。一旦这个储物柜建好了,格子的数量就不能改变了。
|
|||
|
|
|
|||
|
|
### 如何定义数组
|
|||
|
|
在Go语言中,定义数组有多种方式:
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 1. 最基础的定义方式
|
|||
|
|
var scores [3]int // 定义一个能存放3个整数的数组
|
|||
|
|
|
|||
|
|
// 2. 定义时直接赋值
|
|||
|
|
var prices = [3]float64{10.99, 20.99, 30.99}
|
|||
|
|
|
|||
|
|
// 3. 让编译器自动计算长度
|
|||
|
|
names := [...]string{"张三", "李四", "王五"}
|
|||
|
|
|
|||
|
|
// 4. 指定特定位置的值
|
|||
|
|
colors := [5]string{0: "红", 2: "蓝", 4: "绿"} // [红 "" 蓝 "" 绿]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 数组的特点
|
|||
|
|
1. 长度固定:一旦定义,长度不可改变
|
|||
|
|
2. 类型固定:同一个数组只能存储相同类型的元素
|
|||
|
|
3. 长度是类型的一部分:`[3]int`和`[5]int`是不同的类型
|
|||
|
|
|
|||
|
|
### 实战小例子
|
|||
|
|
```go
|
|||
|
|
package main
|
|||
|
|
|
|||
|
|
import "fmt"
|
|||
|
|
|
|||
|
|
func main() {
|
|||
|
|
// 成绩管理系统
|
|||
|
|
var scores [5]int = [5]int{95, 89, 92, 88, 96}
|
|||
|
|
|
|||
|
|
// 计算平均分
|
|||
|
|
sum := 0
|
|||
|
|
for _, score := range scores {
|
|||
|
|
sum += score
|
|||
|
|
}
|
|||
|
|
average := float64(sum) / float64(len(scores))
|
|||
|
|
fmt.Printf("平均分:%.2f\n", average)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
运行结果:
|
|||
|
|
```
|
|||
|
|
平均分:92.00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 切片:灵活的"动态储物柜"
|
|||
|
|
|
|||
|
|
### 为什么需要切片?
|
|||
|
|
如果说数组是固定大小的储物柜,那么切片就像是一个可以随时扩展的"魔法储物柜"。它的大小是可以动态调整的,这让我们在处理不确定数量的数据时更加灵活。
|
|||
|
|
|
|||
|
|
### 切片的创建方式
|
|||
|
|
```go
|
|||
|
|
// 1. 直接创建
|
|||
|
|
fruits := []string{"苹果", "香蕉", "橙子"}
|
|||
|
|
|
|||
|
|
// 2. 使用make函数创建
|
|||
|
|
numbers := make([]int, 3, 5) // 长度为3,容量为5的切片
|
|||
|
|
|
|||
|
|
// 3. 从数组创建
|
|||
|
|
arr := [5]int{1, 2, 3, 4, 5}
|
|||
|
|
slice := arr[1:4] // [2 3 4]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 切片的三个核心概念
|
|||
|
|
1. 指针:指向底层数组的第一个可见元素
|
|||
|
|
2. 长度:切片当前的元素个数(len)
|
|||
|
|
3. 容量:从切片起始位置到底层数组末尾的元素个数(cap)
|
|||
|
|
|
|||
|
|
### 实用的切片操作
|
|||
|
|
```go
|
|||
|
|
package main
|
|||
|
|
|
|||
|
|
import "fmt"
|
|||
|
|
|
|||
|
|
func main() {
|
|||
|
|
// 创建一个购物清单
|
|||
|
|
shoppingList := []string{"牛奶"}
|
|||
|
|
|
|||
|
|
// 添加商品
|
|||
|
|
shoppingList = append(shoppingList, "面包")
|
|||
|
|
shoppingList = append(shoppingList, "水果", "蔬菜")
|
|||
|
|
|
|||
|
|
fmt.Printf("购物清单:%v\n", shoppingList)
|
|||
|
|
fmt.Printf("清单长度:%d\n", len(shoppingList))
|
|||
|
|
fmt.Printf("清单容量:%d\n", cap(shoppingList))
|
|||
|
|
|
|||
|
|
// 复制切片
|
|||
|
|
backup := make([]string, len(shoppingList))
|
|||
|
|
copy(backup, shoppingList)
|
|||
|
|
|
|||
|
|
fmt.Printf("备份清单:%v\n", backup)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
运行结果:
|
|||
|
|
```
|
|||
|
|
购物清单:[牛奶 面包 水果 蔬菜]
|
|||
|
|
清单长度:4
|
|||
|
|
清单容量:4
|
|||
|
|
备份清单:[牛奶 面包 水果 蔬菜]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 切片的注意事项
|
|||
|
|
1. 切片是引用类型,多个切片可能共享同一个底层数组
|
|||
|
|
2. append可能导致重新分配内存,生成新的底层数组
|
|||
|
|
3. 使用make创建切片时,可以指定容量来减少内存重新分配的次数
|
|||
|
|
|
|||
|
|
## 实际应用场景对比
|
|||
|
|
|
|||
|
|
1. 什么时候用数组?
|
|||
|
|
- 当你确切知道数据的长度,且不会改变时
|
|||
|
|
- 例如:存储一周七天的温度数据
|
|||
|
|
|
|||
|
|
2. 什么时候用切片?
|
|||
|
|
- 处理动态数据,如用户输入的列表
|
|||
|
|
- 需要对数据进行频繁的添加和删除操作
|
|||
|
|
- 作为函数参数传递(更加灵活)
|
|||
|
|
|
|||
|
|
## 小结
|
|||
|
|
|
|||
|
|
数组和切片各有特点:数组像是一个固定大小的储物柜,适合存放固定数量的元素;而切片则像是一个可伸缩的储物空间,更适合处理动态数据。在实际开发中,我们更多地使用切片,因为它提供了更好的灵活性和便利性。
|
|||
|
|
|
|||
|
|
记住:选择数组还是切片,关键要看具体的使用场景。理解它们的特点,才能在编程时做出正确的选择。
|