【Go】切片

知识点 关键概念
切片声明 var slice []int
初始化切片 slice := []int{1,2,3}
make() 创建切片 make([]int, len, cap)
获取长度和容量 len(slice), cap(slice)
追加元素 slice = append(slice, value)
切片截取 slice[start:end](返回子切片)
拷贝切片 copy(dest, src)(不会共享底层数组)
删除元素 slice = append(slice[:index], slice[index+1:]...)
nil 切片 vs 空切片 nilSlice == nillen(emptySlice) == 0
切片扩容 超过 cap 后,自动扩容

1. 切片的基本概念

代码示例

go 复制代码
package main

import "fmt"

func main() {
	// 声明切片
	var slice1 []int
	fmt.Println(slice1) // []

	// 直接初始化切片
	slice2 := []int{1, 2, 3, 4, 5}
	fmt.Println(slice2) // [1 2 3 4 5]
}

学习笔记

  • 切片是一种动态数组,可以扩容,而数组长度固定。
  • 切片本质上是对底层数组的引用 ,它存储的是 指向底层数组的指针、长度和容量
  • 切片可以通过 {} 直接初始化,不需要指定长度。

2. 使用 make() 创建切片

代码示例

go 复制代码
package main

import "fmt"

func main() {
	// 创建一个长度为 5 的切片,默认值为 0
	slice1 := make([]int, 5)
	fmt.Println(slice1) // [0 0 0 0 0]

	// 创建一个长度为 7,容量为 10 的切片
	slice2 := make([]int, 7, 10)
	fmt.Println(slice2)                  // [0 0 0 0 0 0 0]
	fmt.Println("长度:", len(slice2))    // 7
	fmt.Println("容量:", cap(slice2))    // 10
}

学习笔记

  • make([]type, len, cap) 用于创建切片 ,其中:
    • len 是切片的初始长度。
    • cap 是切片的容量(可选)。
  • len() 获取切片长度,cap() 获取切片容量
  • 切片长度 <= 容量,超过容量时会自动扩展。

3. 切片的 append() 操作

代码示例

go 复制代码
package main

import "fmt"

func main() {
	slice := []string{"A", "B"}
	slice = append(slice, "C", "D") // 追加元素
	fmt.Println(slice)              // [A B C D]
}

学习笔记

  • append() 用于向切片追加元素 ,如果超出容量,Go 会 自动扩容 并分配新的底层数组。

4. 切片的截取

代码示例

go 复制代码
package main

import "fmt"

func main() {
	slice := []int{1, 2, 3, 4, 5, 6, 7}
	subSlice := slice[1:4] // 从索引 1 截取到索引 4(不包含 4)
	fmt.Println(subSlice)  // [2 3 4]

	subSlice[1] = 100 // 修改 subSlice 会影响原切片
	fmt.Println(slice) // [1 2 100 4 5 6 7]
}

学习笔记

  • slice[start:end] 获取 [start, end) 之间的元素 (不包含 end)。
  • 修改子切片的值会影响原切片,因为它们共用相同的底层数组。

5. 使用 copy() 进行切片拷贝

代码示例

go 复制代码
package main

import "fmt"

func main() {
	src := []int{1, 2, 3, 4, 5}
	dest := make([]int, len(src))

	copy(dest, src) // 复制 src 到 dest
	fmt.Println(dest) // [1 2 3 4 5]

	src[0] = 100
	fmt.Println(src)  // [100 2 3 4 5]
	fmt.Println(dest) // [1 2 3 4 5] (不受影响)
}

学习笔记

  • copy(dest, src) 用于复制切片,不会共享底层数组。
  • 修改 src 不会影响 dest,避免数据被误修改。

6. 切片的删除操作

代码示例

go 复制代码
package main

import "fmt"

func main() {
	slice := []int{1, 2, 3, 4, 5}
	slice = append(slice[:2], slice[3:]...) // 删除索引 2 的元素
	fmt.Println(slice) // [1 2 4 5]
}

学习笔记

  • Go 没有 remove() 方法 ,删除元素时需要使用 append() 将前后部分拼接。
  • slice[:index] + slice[index+1:] 实现删除 ,需要 ... 进行解包。

7. nil 切片 vs 空切片

代码示例

go 复制代码
package main

import "fmt"

func main() {
	var nilSlice []int
	emptySlice := []int{}

	if nilSlice == nil {
		fmt.Println("nilSlice 是 nil")
	}

	if len(emptySlice) == 0 {
		fmt.Println("emptySlice 是空切片")
	}
}

学习笔记

  • nil 切片是未分配内存的切片,值为 nil,常用于表示 "无数据"。
  • 空切片已经初始化,但 len() == 0 ,可以安全使用 append() 添加数据。

8. 切片扩容机制

代码示例

go 复制代码
package main

import "fmt"

func main() {
	slice := []int{}
	fmt.Println("初始容量:", cap(slice))

	for i := 1; i <= 10; i++ {
		slice = append(slice, i)
		fmt.Printf("追加 %d 后,长度: %d, 容量: %d\n", i, len(slice), cap(slice))
	}
}

学习笔记

  • 切片的容量按 2 倍增长
    • len(slice) < cap(slice)append() 直接使用现有的底层数组。
    • 当超出 cap(slice),Go 会 重新分配内存 并扩展容量。

一、go1.18 之前:

1.如果期望容量大于当前容量的两倍就会使用期望容量;

2.如果当前切片的长度小于 1024 就会将容量翻倍;

3.如果当前切片的长度大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;

二、go1.18 之后:

1.如果期望容量大于当前容量的两倍就会使用期望容量;

2.如果当前切片的长度小于阈值(默认 256)就会将容量翻倍;

3.如果当前切片的长度大于等于阈值(默认 256),就会每次增加 25% 的容量,基准是 newcap + 3*threshold,直到新容量大于期望容量;

扩容机制笔记参考自:https://blog.csdn.net/qq_47831505/article/details/135540661

相关推荐
用户2986985301420 分钟前
.NET 文档自动化:Spire.Doc 设置奇偶页页眉/页脚的最佳实践
后端·c#·.net
序安InToo1 小时前
第6课|注释与代码风格
后端·操作系统·嵌入式
xyy1231 小时前
C#: Newtonsoft.Json 到 System.Text.Json 迁移避坑指南
后端
洋洋技术笔记1 小时前
Spring Boot Web MVC配置详解
spring boot·后端
JxWang051 小时前
VS Code 配置 Markdown 环境
后端
navms1 小时前
搞懂线程池,先把 Worker 机制啃明白
后端
JxWang051 小时前
离线数仓的优化及重构
后端
Nyarlathotep01131 小时前
gin01:初探gin的启动
后端·go
JxWang051 小时前
安卓手机配置通用多屏协同及自动化脚本
后端
JxWang051 小时前
Windows Terminal 配置 oh-my-posh
后端