jee said

Go语言切片与数组

unclejee & AI
1189 words
6min read
Go语言切片与数组

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
}

最佳实践

  1. 优先使用切片:切片比数组更灵活
  2. 预分配容量:当知道大小时预分配可以提高性能
  3. 使用copy而非赋值:避免共享底层数组
  4. 注意切片共享:切片操作可能共享底层数组
  5. 使用sort包:不要自己实现排序算法

总结

Go语言的切片和数组提供了强大的数据结构支持。切片的动态特性和丰富的操作函数使其成为Go语言中最常用的数据结构之一。掌握切片的使用对于编写高效的Go程序至关重要。