0
点赞
收藏
分享

微信扫一扫

slice 切片

生活记录馆 2022-04-21 阅读 198
golang

目录

什么是切片

创建切片

1. 通过底层数组 (需要指定上界下界)

2. 直接创建 (直接创建切片, 会在内存中创建一个底层数组, 切片就是对底层数组的引用, 语法糖)

3. 通过make函数创建

切片的长度和容量

 切片默认值(零值)

append 给切片追加元素

切片的扩容规则

 总结


什么是切片

创建切片

1. 通过底层数组 (需要指定上界下界)

  • 切片的上下界有默认值, 上界为0 , 下界为数组或切片的长度
package main

import (
	"fmt"
)

func main() {
	array := [5]int{1,2,3,4,5}
    slice := array[1:4]
	fmt.Printf("array值%v\n", array)
	fmt.Printf("slice值%v\n", slice)
}

2. 直接创建 (直接创建切片, 会在内存中创建一个底层数组, 切片就是对底层数组的引用, 语法糖)

package main

import (
	"fmt"
)

func main() {
	slice := []int{1,2,3}
  var slice2 []int = []int{1,2,3,4}
  var slice3 = []int{1,2,3,4,5}
	fmt.Printf("切片的值是 %v, 类型是 %T\n",slice, slice)
	fmt.Printf("切片的值是 %v, 类型是 %T\n",slice2, slice2)
	fmt.Printf("切片的值是 %v, 类型是 %T",slice3, slice3)
}

3. 通过make函数创建

package main

import (
	"fmt"
)

func main() {
  slice := make([]int, 5,5)
	printSlice(slice)
	for i,_ := range slice {
		slice[i] = i
	}
	printSlice(slice)
}

func printSlice(slice []int) {
  fmt.Println("切片的长度和容量分别是: ", len(slice), cap(slice), "值为", slice)
}

切片的长度和容量

package main

import (
	"fmt"
)

func main() {
  slice := []int{1,2,3,4,5,6,7,8,9}
	printSlice(slice) // 长度9 容量9
	slice2 := slice[:3] // === slice[0:3]
	printSlice(slice2) // 长度3 容量9
	slice3 := slice[1:6]
	printSlice(slice3) // 长度5 容量8
}

func printSlice(slice []int) {
  fmt.Println("切片的长度和容量分别是: ", len(slice), cap(slice))
}

 切片默认值(零值)

package main

import (
	"fmt"
)

func main() {
  var slice []string // 声明未初始化 slice为零值nil
	if (slice == nil) {
		fmt.Println("slice = ", nil)
	}
	slice2 := []string{} // 空切片 != nil
	if slice2 == nil {
		fmt.Println("slice2 = ", nil)
	}
	
	if len(slice) == 0 && len(slice2) == 0 {
		fmt.Println("slice2, slice 都是空切片 ")
	}
}

append 给切片追加元素

官方例子:  

package main

import "fmt"
func main() {
	var s []int
	printSlice(s)
	// 添加一个空切片
	s = append(s, 0)
	printSlice(s)
	// 这个切片会按需增长
	s = append(s, 1)
	printSlice(s)
	// 可以一次性添加多个元素
	s = append(s, 2,3,4,5,6)
	printSlice(s)
}

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

其实前三行打印很好理解, 问题就在于第四行, 为什么我向切片中追加了7个元素, 而切片的容量却是8呢? 其实这是由于切片的扩容规则导致的, 下文会讲

切片的扩容规则

以下部分源码

	newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		if old.cap < 1024 {
			newcap = doublecap
		} else {
			// Check 0 < newcap to detect overflow
			// and prevent an infinite loop.
			for 0 < newcap && newcap < cap {
				newcap += newcap / 4
			}
			// Set newcap to the requested cap when
			// the newcap calculation overflowed.
			if newcap <= 0 {
				newcap = cap
			}
		}
	}

有些时候会遇到不符合上述的规则的情况, 这可能是由于类型导致的

package main

import "fmt"
func main() {
	var s []int32
	printSlice(s)
	s = append(s, 0)
	printSlice(s)
	s = append(s, 1,2)
	printSlice(s)
}

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

 

package main

import "fmt"
func main() {
	var s []int
	printSlice(s)
	s = append(s, 0)
	printSlice(s)
	s = append(s, 1,2)
	printSlice(s)
}

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

可以看到类型的不同确实对容量大小有影响

 文章部分借鉴于 Go slice扩容深度分析 - 掘金本文主要是对go slice的扩容机制进行了一些分析。环境,64位centos的docker镜像+go1.12.1。 网上很多博客也有提到,slice扩容,cap不够1024的,直接翻倍;cap超过1024的,新cap变为老cap的1.25倍。 应该是4个8?基于翻倍的思路,c…https://juejin.cn/post/6844903812331732999

 总结

举报

相关推荐

0 条评论