Go 中切片(Slice)的长度与容量(Go语言中切片长度与容量的详解)
原创
一、切片概述
在 Go 语言中,切片(Slice)是一种内置的数据结构,用于存储一系列元素。切片是一种动态数组,其内部结构由指向底层数组的指针、长度和容量组成。切片提供了灵活的数组操作做法,可以动态地增多或降低元素数量。
二、切片的长度与容量
切片的长度是指切片中元素的个数,可以通过内置函数 `len()` 获取。容量是指切片底层数组能够容纳的元素个数,可以通过内置函数 `cap()` 获取。下面通过一个例子来明白切片的长度与容量。
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
fmt.Println("len(s):", len(s)) // 输出: len(s): 3
fmt.Println("cap(s):", cap(s)) // 输出: cap(s): 3
}
在上面的例子中,切片 `s` 的长度为 3,容量也为 3。接下来,我们将通过几个例子来详细探讨切片的长度与容量之间的关系。
三、切片的创建与长度、容量变化
1. 使用字面量创建切片
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
fmt.Println("len(s):", len(s)) // 输出: len(s): 3
fmt.Println("cap(s):", cap(s)) // 输出: cap(s): 3
}
2. 使用内置函数 `make()` 创建切片
package main
import "fmt"
func main() {
s := make([]int, 3)
fmt.Println("len(s):", len(s)) // 输出: len(s): 3
fmt.Println("cap(s):", cap(s)) // 输出: cap(s): 3
}
3. 使用切片字面量创建切片
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
fmt.Println("len(s):", len(s)) // 输出: len(s): 3
fmt.Println("cap(s):", cap(s)) // 输出: cap(s): 3
}
4. 使用切片的切片
package main
import "fmt"
func main() {
s := []int{1, 2, 3, 4, 5}
s1 := s[1:3]
fmt.Println("len(s1):", len(s1)) // 输出: len(s1): 2
fmt.Println("cap(s1):", cap(s1)) // 输出: cap(s1): 4
}
在上面的例子中,`s1` 是 `s` 的一个切片,包含 `s` 的索引 1 到 2 的元素。`s1` 的长度为 2,容量为 4,这是由于 `s1` 底层的数组是 `s` 的底层数组,从索引 1 开端,直到数组的末尾。
四、切片扩容
当切片的长度约为容量时,如果继续向切片添加元素,Go 语言会自动扩容切片。下面是一个切片扩容的例子:
package main
import "fmt"
func main() {
s := make([]int, 3)
s = append(s, 4, 5, 6)
fmt.Println("len(s):", len(s)) // 输出: len(s): 6
fmt.Println("cap(s):", cap(s)) // 输出: cap(s): 6
}
在上面的例子中,我们创建了一个长度为 3 的切片 `s`,然后通过 `append()` 函数向切片中添加了 3 个元素。由于 `s` 的容量也是 3,从而 Go 语言会自动扩容切片,使其长度和容量都变为 6。
五、切片扩容规则
当切片扩容时,Go 语言遵循以下规则:
- 如果切片的容量小于 1024,新容量将是原容量的两倍。
- 如果切片的容量大于或等于 1024,新容量将是原容量的 1.25 倍,再加上一个较小的数,以确保新容量至少比原长度大。
- 如果切片的容量非常大,新容量将是原容量的 1.125 倍,再加上一个较小的数。
这些规则是为了平衡内存使用和性能。了解这些规则可以帮助我们更好地预测切片扩容时的内存使用情况。
六、切片的内存优化
由于切片在扩容时会创建新的底层数组,故而频繁的扩容操作大概会致使内存分配和释放,从而影响性能。以下是一些优化切片内存使用的方法:
- 预先分配足够大的切片容量,以降低扩容操作。
- 使用切片时,尽量降低不必要的切片操作,例如切片的切片。
- 在循环中,重用切片,而不是每次迭代都创建新的切片。
七、总结
切片是 Go 语言中一种非常重要的数据结构,明白切片的长度和容量对于编写高效和内存友好的 Go 程序至关重要。通过本文的介绍,我们了解了切片的创建、长度、容量变化、扩容规则以及内存优化方法。愿望这些内容能够帮助读者更好地使用 Go 语言的切片。