cap vs len of slice in golang

huangapple go评论84阅读模式
英文:

cap vs len of slice in golang

问题

切片(slice)在Go语言中有长度(len)和容量(cap)两个概念。

切片的长度(len)是指切片中实际包含的元素个数。

切片的容量(cap)是指底层数组中从切片的第一个元素开始算起,到数组末尾的元素个数。

例如:

x := make([]int, 0, 5) // len(x)=0, cap(x)=5

len表示的是切片中非空值的个数吗?

英文:

What is the difference between cap and len of a slice in golang?

According to definition:

A slice has both a length and a capacity.

The length of a slice is the number of elements it contains.

The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice.

x := make([]int, 0, 5) // len(b)=0, cap(b)=5

Does the len mean non null values only?

答案1

得分: 181

切片是一种抽象,它在底层使用数组。

cap 表示底层数组的容量。len 表示数组中的元素个数。

Go 语言中的切片抽象非常好用,因为它会自动调整底层数组的大小,而且在 Go 语言中数组是不可调整大小的,所以几乎总是使用切片。

示例:

s := make([]int, 0, 3)
for i := 0; i < 5; i++ {
	s = append(s, i)
	fmt.Printf("cap %v, len %v, %p\n", cap(s), len(s), s)
}

输出结果类似于:

cap 3, len 1, 0x1040e130
cap 3, len 2, 0x1040e130
cap 3, len 3, 0x1040e130
cap 6, len 4, 0x10432220
cap 6, len 5, 0x10432220

可以看到,一旦达到容量上限,append 函数会返回一个具有更大容量的新切片。在第四次迭代时,你会注意到容量增加了,并且有一个新的指针地址。

运行示例

我知道你没有问关于数组和 append 函数的问题,但它们对理解切片和内置函数的原因非常基础。

英文:

A slice is an abstraction that uses an array under the covers.

cap tells you the capacity of the underlying array. len tells you how many items are in the array.

The slice abstraction in Go is very nice since it will resize the underlying array for you, plus in Go arrays cannot be resized so slices are almost always used instead.

Example:

s := make([]int, 0, 3)
for i := 0; i &lt; 5; i++ {
	s = append(s, i)
	fmt.Printf(&quot;cap %v, len %v, %p\n&quot;, cap(s), len(s), s)
}

Will output something like this:

cap 3, len 1, 0x1040e130
cap 3, len 2, 0x1040e130
cap 3, len 3, 0x1040e130
cap 6, len 4, 0x10432220
cap 6, len 5, 0x10432220

As you can see once the capacity is met, append will return a new slice with a larger capacity. On the 4th iteration you will notice a larger capacity and a new pointer address.

Play example

I realize you did not ask about arrays and append but they are pretty foundational in understanding the slice and the reason for the builtins.

答案2

得分: 12

源代码中:

// len内置函数根据其类型返回v的长度:
// 数组:v中的元素数量。
// 指向数组的指针:*v中的元素数量(即使v为nil)。
// 切片或映射:v中的元素数量;如果v为nil,则len(v)为零。
// 字符串:v中的字节数量。
// 通道:通道缓冲区中排队(未读)的元素数量;
// 如果v为nil,则len(v)为零。
func len(v Type) int

// cap内置函数根据其类型返回v的容量:
// 数组:v中的元素数量(与len(v)相同)。
// 指向数组的指针:*v中的元素数量(与len(v)相同)。
// 切片:重新切片时切片可以达到的最大长度;
// 如果v为nil,则cap(v)为零。
// 通道:通道缓冲区的容量,以元素为单位;
// 如果v为nil,则cap(v)为零。
func cap(v Type) int
英文:

From the source code:

// The len built-in function returns the length of v, according to its type:
//	Array: the number of elements in v.
//	Pointer to array: the number of elements in *v (even if v is nil).
//	Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
//	String: the number of bytes in v.
//	Channel: the number of elements queued (unread) in the channel buffer;
//	if v is nil, len(v) is zero.
func len(v Type) int

// The cap built-in function returns the capacity of v, according to its type:
//	Array: the number of elements in v (same as len(v)).
//	Pointer to array: the number of elements in *v (same as len(v)).
//	Slice: the maximum length the slice can reach when resliced;
//	if v is nil, cap(v) is zero.
//	Channel: the channel buffer capacity, in units of elements;
//	if v is nil, cap(v) is zero.
func cap(v Type) int

答案3

得分: 3

简单解释
切片是数组的自增长形式,因此有两个主要属性。

长度是切片中元素的总数,可以用于循环遍历我们存储在切片中的元素。当我们打印切片时,会打印出长度范围内的所有元素。

容量是底层数组中的元素总数,在追加更多元素时,长度会增加到容量。在此之后,对切片的进一步追加会自动增加容量(大约是原容量的两倍),并增加相应数量的长度。

真正的魔力在于从切片中切出子切片,所有实际的读写操作都在底层数组上进行。因此,对子切片的任何更改都会同时改变原始切片和底层数组中的数据。而子切片可以具有自己的长度和容量。

仔细阅读下面的程序。这是对golang tour示例的修改版本。

package main

import "fmt"

func main() {
    sorig := []int{2, 3, 5, 7, 11, 13}
    printSlice(sorig)

    // 切片切割,使其长度为零。
    s := sorig[:0]
    printSlice(s)

    // 增加长度。
    s = s[:4]
    s[2] = 555
    printSlice(s)

    // 删除前两个值。
    s = s[2:]
    printSlice(s)
    
    printSlice(sorig)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

// 输出
// len=6 cap=6 [2 3 5 7 11 13]
// len=0 cap=6 []
// len=4 cap=6 [2 3 555 7]
// len=2 cap=4 [555 7]
// len=6 cap=6 [2 3 555 7 11 13]
英文:

Simple explanation
Slice are self growing form of array so there are two main properties.

Length is total no of elements() the slice is having and can be used for looping through the elements we stored in slice. Also when we print the slice all elements till length gets printed.

Capacity is total no elements in underlying array, when you append more elements the length increases till capacity. After that any further append to slice causes the capacity to increase automatically(apprx double) and length by no of elements appended.

The real magic happens when you slice out sub slices from a slice where all the actual read/write happens on the underlaying array. So any change in sub slice will also change data both in original slice and underlying array. Where as any sub slices can have their own length and capacity.

Go through the below program carefully. Its modified version of golang tour example

package main

import &quot;fmt&quot;

func main() {
	sorig := []int{2, 3, 5, 7, 11, 13}
	printSlice(sorig)

	// Slice the slice to give it zero length.
	s := sorig[:0]
	printSlice(s)

	// Extend its length.
	s = s[:4]
	s[2] = 555
	printSlice(s)

	// Drop its first two values.
	s = s[2:]
	printSlice(s)
	
	printSlice(sorig)
}

func printSlice(s []int) {
	fmt.Printf(&quot;len=%d cap=%d %v\n&quot;, len(s), cap(s), s)

//Output
//len=6 cap=6 [2 3 5 7 11 13]
//len=0 cap=6 []
//len=4 cap=6 [2 3 555 7]
//len=2 cap=4 [555 7]
//len=6 cap=6 [2 3 555 7 11 13]

huangapple
  • 本文由 发表于 2017年1月16日 08:51:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/41668053.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定