Golang中切片的长度和容量的区别

Golang中切片的长度和容量的区别

首先要知道在Golang中,切片的底层实际就是数组。

1.切片的长度:

切片的长度指切片中元素的数量,可以使用len()函数查询其切片的长度。

示例1:

package main

import "fmt"

func main(){
    slice := []int{1,3,2,6,4}
    # 调用len查看长度
    length := len(slice)
    fmt.Printf("slice01的长度是:%v", length)
}

// 输出结果
// slice的长度是:5

在上面代码中,变量length就是切片的长度(结果是5)

2.切片的容量:

切片的容量是指切片底层数组的长度,可以使用cap()函数查看容量

示例2:

package main

import "fmt"

func main(){
    slice := []int{1,3,2,6,4}
    // 调用cap查看容量
    capacity := cap(slice)
    fmt.Printf("slice01的容量是:%v", capacity)
}

// 输出结果
// slice的容量是:5

在上面代码中,变量capacity就是切片的容量(结果也是5)

3.通过上面两个示例看不出区别,我们看下面的示例:

示例3

package main

import "fmt"

func main(){
    // 通过make函数来创建slice, 4表示切片的长度, 10标识切片的容量
    slice := make([]int, 4, 6)
    length := len(slice)
    capacity := cap(slice)
    fmt.Printf("slice01的长度是:%v\n", length)
    fmt.Printf("slice01的容量是:%v\n", capacity)
}

// 输出结果
// slice01的长度是:4
// slice01的容量是:6

你可以想象成:当执行slice := make([]int, 4, 10)的时候,程序在底层创建了一个长度为6的数组,切片slice引用了前面4个元素,就生成了slice这个切片,当前切片值是:{0, 0, 0, 0},剩下的2个元素则暂时没有引用。

4.通过对切片的增加,查看切片与底层数组的变化

我们知道,golang中切片和数组的主要区别在于数组是定长的,切片是变长的。但我们在示例3中定义了切片的容量是6,那如果超过6个元素了,将会发生什么呢?

示例4

package main

import "fmt"

func main(){
    // 通过make函数来创建slice, 4表示切片的长度, 10标识切片的容量
    slice := make([]int, 4, 6)
    length := len(slice)
    capacity := cap(slice)
    fmt.Printf("slice01的长度是:%v\n", length)
    fmt.Printf("slice01的容量是:%v\n", capacity)
    
    //第一次向切片slice内添加元素
    slice = append(slice, 1)
    //打印slice的长度,容量,内存地址(slice[0]的内存地址)
    fmt.Printf("\n\n第一次结果:")
    fmt.Printf("slice的长度是:%v\n", len(slice))
    fmt.Printf("slice的容量是:%v\n", cap(slice))
    fmt.Printf("slice的内存地址是:%v\n", &slice[0])
    
    // 第二次向slice内添加元素
    slice = append(slice, 1)
    //打印slice的长度,容量,内存地址(slice[0]的内存地址)
    fmt.Printf("\n\n第二次结果:")
    fmt.Printf("slice的长度是:%v\n", len(slice))
    fmt.Printf("slice的容量是:%v\n", cap(slice))
    fmt.Printf("slice的内存地址是:%v\n", &slice[0])
    
    // 第三次向slice内添加元素
    slice = append(slice, 1)
    //打印slice的长度,容量,内存地址(slice[0]的内存地址)
    fmt.Printf("\n\n第三次结果:")
    fmt.Printf("slice的长度是:%v\n", len(slice))
    fmt.Printf("slice的容量是:%v\n", cap(slice))
    fmt.Printf("slice的内存地址是:%v\n", &slice[0])
}

// slice01的长度是:4
// slice01的容量是:6


// 第一次结果:slice的长度是:5
// slice的容量是:6
// slice的内存地址是:0xc00000e390


// 第二次结果:slice的长度是:6
// slice的容量是:6
// slice的内存地址是:0xc00000e390


// 第三次结果:slice的长度是:7
// slice的容量是:12
// slice的内存地址是:0xc000060060

通过示例4我们可以发现:我们初始化切片长度为4, 容量为6的时候。

当第一次和第二次向切片内添加元素后,只有切片的长度增加,容量和内存地址都没改变

当第三次向切片内添加元素后,长度增加了1,容量变成了之前的2倍,内存地址也发生了改变。

由此我们可以推断出:

**总结:**当切片的元素长度超过了默认的容量之后,程序会重新创建一个底层数组和切片绑定,且新的数组的长度为原来的两倍(切片的容量变成原来的两倍)

5. 注意用法:

示例5

package main

import "fmt"

func main() {
	slice := make([]int, 4, 4)
	slice2 := make([]int, 4, 5)
    // 调用下方定义的test函数
	test(slice)
	test(slice2)

	// 输出两个切片调用test函数后的结果
	fmt.Printf("slice的结果: %v\n", slice)
	fmt.Printf("slice2的结果: %v\n", slice2)

}

func test(s []int) {
	s = append(s, 1)
	for i := 0; i < len(s); i++ {
		s[i] = 100
	}
}

// slice的结果: [0 0 0 0]
// slice2的结果: [100 100 100 100]

切片容量不同,导致了最终结果不同。

我的主页:http://blog.nexk.top

你可能感兴趣的:(golang,golang)