ZetCode

Golang cap 函数

最后修改时间 2025 年 5 月 8 日

本教程将解释如何在 Go 中使用内置的 cap 函数。我们将通过实际容量使用示例来介绍切片和数组的容量。

cap 函数返回 Go 中切片或数组的容量。容量表示底层数组可以容纳的最大元素数量。对于数组,容量始终等于长度。

在 Go 中,cap 主要用于切片,以了解其增长潜力。了解切片的容量有助于优化内存使用和性能。

基本数组容量示例

对于数组,cap 始终返回与 len 相同的值。本示例通过固定大小的数组演示容量。
注意:数组的容量在声明时已固定。

array_cap.go
package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}
    
    fmt.Println("Array:", arr)
    fmt.Println("Length:", len(arr))
    fmt.Println("Capacity:", cap(arr)) // Same as length for arrays
}

数组的大小固定为 5,因此长度和容量均为 5。声明后,数组的容量无法更改。

切片容量基础

切片可以在需要重新分配之前增长到其容量。本示例显示了切片容量与长度的不同。

slice_cap.go
package main

import "fmt"

func main() {
    s := make([]int, 3, 5) // length 3, capacity 5
    
    fmt.Println("Slice:", s)
    fmt.Println("Length:", len(s))
    fmt.Println("Capacity:", cap(s))
    
    s = append(s, 4)
    fmt.Println("\nAfter append:")
    fmt.Println("Length:", len(s))
    fmt.Println("Capacity:", cap(s)) // Still 5
}

切片的初始长度为 3,但容量为 5。追加一个元素后,长度变为 4,而容量保持为 5。

追加时的容量增长

当切片超出其容量时,Go 会自动分配一个更大的新数组。本示例演示了追加操作期间容量的增长。

capacity_growth.go
package main

import "fmt"

func main() {
    s := make([]int, 0, 2) // length 0, capacity 2
    
    fmt.Printf("Initial cap: %d\n", cap(s))
    
    s = append(s, 1)
    s = append(s, 2)
    fmt.Printf("After 2 appends cap: %d\n", cap(s))
    
    s = append(s, 3) // Exceeds capacity
    fmt.Printf("After 3rd append cap: %d\n", cap(s)) // Capacity doubles
}

当超出初始容量时,Go 通常会使容量加倍。这种增长模式有助于分摊多次追加操作的分配成本。

切片表达式的容量

切片操作对容量的影响不同。本示例说明了切片如何影响容量计算。

slice_expression_cap.go
package main

import "fmt"

func main() {
    original := make([]int, 5, 10) // length 5, capacity 10
    
    // Full slice
    fmt.Printf("Original cap: %d\n", cap(original))
    
    // Slice from index 2
    slice1 := original[2:]
    fmt.Printf("Slice from 2 cap: %d\n", cap(slice1)) // 8 (10-2)
    
    // Slice from index 2 to 4
    slice2 := original[2:4]
    fmt.Printf("Slice 2:4 cap: %d\n", cap(slice2)) // Still 8
}

切片根据起始索引影响容量。容量将等于原始容量减去切片的起始索引。

实际容量使用

了解容量有助于优化切片操作。本示例使用容量进行预分配以提高性能。

preallocate_slice.go
package main

import (
    "fmt"
    "time"
)

func processWithoutPreallocation(n int) {
    start := time.Now()
    var s []int
    
    for i := 0; i < n; i++ {
        s = append(s, i)
    }
    elapsed := time.Since(start)
    fmt.Printf("Without preallocation: %v\n", elapsed)
}

func processWithPreallocation(n int) {
    start := time.Now()
    s := make([]int, 0, n) // Preallocate capacity
    
    for i := 0; i < n; i++ {
        s = append(s, i)
    }
    elapsed := time.Since(start)
    fmt.Printf("With preallocation: %v\n", elapsed)
}

func main() {
    const size = 1000000
    processWithoutPreallocation(size)
    processWithPreallocation(size)
}

预分配容量可以避免在追加操作期间重复分配。这显著提高了大型切片的性能。

来源

Go 语言规范

本教程通过数组和切片实际容量使用示例,介绍了 Go 中的 cap 函数。

作者

我叫 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Golang 教程