jee said
Go语言切片与数组
Go语言的切片和数组是重要的数据结构。数组是固定长度的,而切片是动态长度的,这使得切片在实际开发中更加常用。
数组
数组定义
// 声明数组
var arr1 [5]int
arr2 := [5]int{1, 2, 3, 4, 5}
arr3 := [...]string{"a", "b", "c"} // 自动计算长度
// 多维数组
matrix := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}数组特性
- 固定长度:长度是类型的一部分
- 值类型:数组赋值会复制整个数组
- 内存连续:数组元素在内存中连续存储
func modifyArray(arr [3]int) {
arr[0] = 100
}
func main() {
arr := [3]int{1, 2, 3}
modifyArray(arr)
fmt.Println(arr) // [1 2 3],原数组未被修改
}切片
切片定义
// 声明切片
var s1 []int
s2 := []int{1, 2, 3, 4, 5}
s3 := make([]int, 5) // 创建长度为5的切片
s4 := make([]int, 0, 10) // 创建长度为0,容量为10的切片切片操作
s := []int{1, 2, 3, 4, 5}
// 获取元素
fmt.Println(s[0]) // 1
// 切片操作
fmt.Println(s[1:3]) // [2 3],从索引1到3(不包括3)
fmt.Println(s[:3]) // [1 2 3],从开始到3
fmt.Println(s[2:]) // [3 4 5],从2到结束
fmt.Println(s[:]) // [1 2 3 4 5],整个切片切片追加
s := []int{1, 2, 3}
// 追加单个元素
s = append(s, 4) // [1 2 3 4]
// 追加多个元素
s = append(s, 5, 6) // [1 2 3 4 5 6]
// 追加另一个切片
s2 := []int{7, 8, 9}
s = append(s, s2...) // [1 2 3 4 5 6 7 8 9]切片删除
s := []int{1, 2, 3, 4, 5}
// 删除第一个元素
s = s[1:] // [2 3 4 5]
// 删除最后一个元素
s = s[:len(s)-1] // [1 2 3 4]
// 删除指定索引的元素
index := 2
s = append(s[:index], s[index+1:] // [1 2 4 5]切片容量
切片扩容
s := make([]int, 0, 3)
fmt.Printf("长度: %d, 容量: %d\n", len(s), cap(s))
// 长度: 0, 容量: 3
s = append(s, 1)
fmt.Printf("长度: %d, 容量: %d\n", len(s), cap(s))
// 长度: 1, 容量: 3
s = append(s, 2, 3, 4)
fmt.Printf("长度: %d, 容量: %d\n", len(s), cap(s))
// 长度: 4, 容量: 6(容量自动扩容)预分配容量
// 好的做法:预分配容量
s := make([]int, 0, 100)
for i := 0; i < 100; i++ {
s = append(s, i)
}
// 不好的做法:频繁扩容
s2 := []int{}
for i := 0; i < 100; i++ {
s2 = append(s2, i)
}切片复制
使用copy函数
src := []int{1, 2, 3, 4, 5}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst) // [1 2 3 4 5]切片克隆
s1 := []int{1, 2, 3}
// 使用append克隆
s2 := append([]int{}, s1...)
// 使用make和copy克隆
s3 := make([]int, len(s1))
copy(s3, s1)切片排序
使用sort包
import "sort"
s := []int{5, 2, 8, 1, 9, 3}
// 升序排序
sort.Ints(s)
fmt.Println(s) // [1 2 3 5 8 9]
// 降序排序
sort.Sort(sort.Reverse(sort.IntSlice(s)))
fmt.Println(s) // [9 8 5 3 2 1]
// 字符串切片排序
strs := []string{"c", "a", "b"}
sort.Strings(strs)
fmt.Println(strs) // [a b c]切片与数组转换
数组转切片
arr := [5]int{1, 2, 3, 4, 5}
s := arr[:]
fmt.Printf("数组长度: %d\n", len(arr)) // 5
fmt.Printf("切片长度: %d\n", len(s)) // 5切片转数组
s := []int{1, 2, 3}
// 转换为数组
arr := [3]int(s)
fmt.Println(arr) // [1 2 3]常用模式
过滤切片
func filterEven(numbers []int) []int {
result := []int{}
for _, num := range numbers {
if num%2 == 0 {
result = append(result, num)
}
}
return result
}
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
evens := filterEven(nums)
fmt.Println(evens) // [2 4 6]
}映射切片
func square(numbers []int) []int {
result := make([]int, len(numbers))
for i, num := range numbers {
result[i] = num * num
}
return result
}
func main() {
nums := []int{1, 2, 3, 4, 5}
squares := square(nums)
fmt.Println(squares) // [1 4 9 16 25]
}归约切片
func sum(numbers []int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func main() {
nums := []int{1, 2, 3, 4, 5}
total := sum(nums)
fmt.Println(total) // 15
}最佳实践
- 优先使用切片:切片比数组更灵活
- 预分配容量:当知道大小时预分配可以提高性能
- 使用copy而非赋值:避免共享底层数组
- 注意切片共享:切片操作可能共享底层数组
- 使用sort包:不要自己实现排序算法
总结
Go语言的切片和数组提供了强大的数据结构支持。切片的动态特性和丰富的操作函数使其成为Go语言中最常用的数据结构之一。掌握切片的使用对于编写高效的Go程序至关重要。