【Go 1.26.4】Golang Slice 深度解析

Golang Slice 深度解析

基于 Go 1.26.4 源码,源码路径:github.com/go-go1.26.4

核心源文件:runtime/slice.goreflect/value.go


1 slice 功能完整介绍

1.1 语法定义与核心概念

Go 切片(slice)是对底层数组的引用视图,由三个字段组成:指针、长度、容量。

go 复制代码
// 声明(零值 nil)
var s []int                    // s == nil, len=0, cap=0

// make 初始化
s = make([]int, 5)            // len=5, cap=5, 元素全为0
s = make([]int, 3, 10)        // len=3, cap=10

// 字面量初始化
s := []int{1, 2, 3}           // len=3, cap=3
s := []int{10: -1}            // len=11, cap=11, s[10]=-1 其余为0

// 从数组切片
arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:3]                 // len=2, cap=4, s=[2,3]

// new(只分配 slice header,不分配底层数组)
sp := new([]int)              // *[]int, *sp == nil

1.2 slice vs array 核心区别

维度 Array [n]T Slice []T
长度 编译期固定,属于类型 运行时可变
内存 值类型,直接存储数据 引用类型,3个字段(24字节)
赋值 拷贝全部数据 拷贝 header(共享底层数组)
传参 拷贝整份数组 拷贝 header(高效)
nil 不存在 nil nil slice 合法
比较 可用 == 比较 不可用 == 比较(只能与 nil 比)
零值 元素全为零值 nil

1.3 适用场景

#mermaid-svg-mxRpxGPTrqcq7lpl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mxRpxGPTrqcq7lpl .error-icon{fill:#552222;}#mermaid-svg-mxRpxGPTrqcq7lpl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mxRpxGPTrqcq7lpl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mxRpxGPTrqcq7lpl .marker.cross{stroke:#333333;}#mermaid-svg-mxRpxGPTrqcq7lpl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mxRpxGPTrqcq7lpl p{margin:0;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge{stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .section--1 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section--1 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section--1 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section--1 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section--1 text{fill:#ffffff;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth--1{stroke-width:17;}#mermaid-svg-mxRpxGPTrqcq7lpl .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-0 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-0 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-0 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-0 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-0 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-0{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-0{stroke-width:14;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-1 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-1 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-1 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-1 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-1 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-1{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-1{stroke-width:11;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 text{fill:#ffffff;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-2{stroke-width:8;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-3 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-3 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-3 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-3 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-3 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-3{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-3{stroke-width:5;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-4 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-4 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-4 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-4 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-4 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-4{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-4{stroke-width:2;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-5 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-5 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-5 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-5 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-5 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-5{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-5{stroke-width:-1;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-6 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-6 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-6 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-6 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-6 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-6{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-6{stroke-width:-4;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-7 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-7 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-7 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-7 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-7 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-7{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-7{stroke-width:-7;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-8 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-8 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-8 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-8 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-8 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-8{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-8{stroke-width:-10;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-9 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-9 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-9 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-9 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-9 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-9{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-9{stroke-width:-13;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-10 rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-10 path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-10 circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-10 polygon,#mermaid-svg-mxRpxGPTrqcq7lpl .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-10 text{fill:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .node-icon-10{font-size:40px;color:black;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .edge-depth-10{stroke-width:-16;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled circle,#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:lightgray;}#mermaid-svg-mxRpxGPTrqcq7lpl .disabled text{fill:#efefef;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-root rect,#mermaid-svg-mxRpxGPTrqcq7lpl .section-root path,#mermaid-svg-mxRpxGPTrqcq7lpl .section-root circle,#mermaid-svg-mxRpxGPTrqcq7lpl .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-mxRpxGPTrqcq7lpl .section-root text{fill:#ffffff;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-root span{color:#ffffff;}#mermaid-svg-mxRpxGPTrqcq7lpl .section-2 span{color:#ffffff;}#mermaid-svg-mxRpxGPTrqcq7lpl .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-mxRpxGPTrqcq7lpl .edge{fill:none;}#mermaid-svg-mxRpxGPTrqcq7lpl .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-mxRpxGPTrqcq7lpl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Go Slice 适用场景
动态集合
不确定元素数量
频繁增删
函数参数
避免数组拷贝
传切片而非数组
字符串处理
byte切片操作
rune切片转换
IO缓冲区
读取写入缓冲
零拷贝切片引用
数据管道
生产者append
消费者slice消费


2 底层 runtime 实现原理

2.1 slice 底层结构体完整字段

源码位置:runtime/slice.go:14

go 复制代码
type slice struct {
    array unsafe.Pointer  // ★ 指向底层数组的指针
    len   int             // ★ 当前元素数量
    cap   int             // ★ 底层数组容量(从 array 起始到末尾的元素数)
}

内存布局(64-bit 系统,24 bytes)

复制代码
slice header (24 bytes on 64-bit)
┌────────────────────────────────────────────────────┐
│  array   unsafe.Pointer  (8B)  ──→ 底层数组首地址   │
├────────────────────────────────────────────────────┤
│  len     int             (8B)  │ 当前长度            │
├────────────────────────────────────────────────────┤
│  cap     int             (8B)  │ 容量                │
└────────────────────────────────────────────────────┘

底层数组:
  array ──→ [elem0][elem1][elem2]...[elem_len-1][ ... 已分配但未使用 ... ]
            │←──── len ────→│       │←──── cap - len ────→│
            │←──────────────── cap ──────────────────────→│

三种 slice 状态的内存布局

复制代码
1. nil slice:
   ┌───────────┐
   │ array=nil │
   │ len   = 0 │
   │ cap   = 0 │
   └───────────┘
   底层数组: 无
   s == nil → true

2. 空 slice (make([]int, 0) 或 s[:0]):
   ┌──────────────────────┐
   │ array = &zerobase    │  ← 指向全局零值地址
   │ len   = 0            │
   │ cap   = 0            │
   └──────────────────────┘
   底层数组: zerobase(全局唯一的零字节)
   s == nil → false  ★ 注意区别!

3. 正常 slice:
   ┌──────────────────────┐     ┌────┬────┬────┬────┬────┬────┐
   │ array ────────────── │────→│ 10 │ 20 │ 30 │ 0  │ 0  │ 0  │
   │ len   = 3            │     └────┴────┴────┴────┴────┴────┘
   │ cap   = 6            │      [0]  [1]  [2]  [3]  [4]  [5]
   └──────────────────────┘      │←─ len ─→│←── 可增长 ──→│
                                  │←──────── cap ──────────→│

2.2 makeslice------创建切片的内存分配

源码位置:runtime/slice.go:57

go 复制代码
func makeslice(et *_type, len, cap int) unsafe.Pointer {
    // ★ 计算所需内存 = cap × elemSize
    mem, overflow := math.MulUintptr(et.Size_, uintptr(cap))
    
    // ★ 溢出或超过最大分配或参数非法 → panic
    if overflow || mem > maxAlloc || len < 0 || len > cap {
        mem, overflow := math.MulUintptr(et.Size_, uintptr(len))
        if overflow || mem > maxAlloc || len < 0 {
            panicmakeslicelen()   // panic: makeslice: len out of range
        }
        panicmakeslicecap()       // panic: makeslice: cap out of range
    }

    // ★ 分配内存
    return mallocgc(mem, et, true)
    // mallocgc 第三个参数 true = 需要零初始化
    // 如果 et 包含指针,GC 会扫描这块内存
}

#mermaid-svg-thijnvge6LkijG7x{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-thijnvge6LkijG7x .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-thijnvge6LkijG7x .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-thijnvge6LkijG7x .error-icon{fill:#552222;}#mermaid-svg-thijnvge6LkijG7x .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-thijnvge6LkijG7x .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-thijnvge6LkijG7x .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-thijnvge6LkijG7x .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-thijnvge6LkijG7x .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-thijnvge6LkijG7x .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-thijnvge6LkijG7x .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-thijnvge6LkijG7x .marker{fill:#333333;stroke:#333333;}#mermaid-svg-thijnvge6LkijG7x .marker.cross{stroke:#333333;}#mermaid-svg-thijnvge6LkijG7x svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-thijnvge6LkijG7x p{margin:0;}#mermaid-svg-thijnvge6LkijG7x .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-thijnvge6LkijG7x .cluster-label text{fill:#333;}#mermaid-svg-thijnvge6LkijG7x .cluster-label span{color:#333;}#mermaid-svg-thijnvge6LkijG7x .cluster-label span p{background-color:transparent;}#mermaid-svg-thijnvge6LkijG7x .label text,#mermaid-svg-thijnvge6LkijG7x span{fill:#333;color:#333;}#mermaid-svg-thijnvge6LkijG7x .node rect,#mermaid-svg-thijnvge6LkijG7x .node circle,#mermaid-svg-thijnvge6LkijG7x .node ellipse,#mermaid-svg-thijnvge6LkijG7x .node polygon,#mermaid-svg-thijnvge6LkijG7x .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-thijnvge6LkijG7x .rough-node .label text,#mermaid-svg-thijnvge6LkijG7x .node .label text,#mermaid-svg-thijnvge6LkijG7x .image-shape .label,#mermaid-svg-thijnvge6LkijG7x .icon-shape .label{text-anchor:middle;}#mermaid-svg-thijnvge6LkijG7x .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-thijnvge6LkijG7x .rough-node .label,#mermaid-svg-thijnvge6LkijG7x .node .label,#mermaid-svg-thijnvge6LkijG7x .image-shape .label,#mermaid-svg-thijnvge6LkijG7x .icon-shape .label{text-align:center;}#mermaid-svg-thijnvge6LkijG7x .node.clickable{cursor:pointer;}#mermaid-svg-thijnvge6LkijG7x .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-thijnvge6LkijG7x .arrowheadPath{fill:#333333;}#mermaid-svg-thijnvge6LkijG7x .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-thijnvge6LkijG7x .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-thijnvge6LkijG7x .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-thijnvge6LkijG7x .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-thijnvge6LkijG7x .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-thijnvge6LkijG7x .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-thijnvge6LkijG7x .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-thijnvge6LkijG7x .cluster text{fill:#333;}#mermaid-svg-thijnvge6LkijG7x .cluster span{color:#333;}#mermaid-svg-thijnvge6LkijG7x div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-thijnvge6LkijG7x .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-thijnvge6LkijG7x rect.text{fill:none;stroke-width:0;}#mermaid-svg-thijnvge6LkijG7x .icon-shape,#mermaid-svg-thijnvge6LkijG7x .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-thijnvge6LkijG7x .icon-shape p,#mermaid-svg-thijnvge6LkijG7x .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-thijnvge6LkijG7x .icon-shape .label rect,#mermaid-svg-thijnvge6LkijG7x .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-thijnvge6LkijG7x .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-thijnvge6LkijG7x .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-thijnvge6LkijG7x :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Yes
No
make(\[\]int, 3, 10)
makeslice(int类型, len=3, cap=10)
计算 mem = 10 * 8 = 80 bytes
overflow || mem > maxAlloc?
panic
mallocgc(80, int类型, true)
返回底层数组指针
构造 slice{array:指针, len:3, cap:10}

makeslicecopy------append 触发的创建+拷贝

源码位置:runtime/slice.go:28

go 复制代码
func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer {
    var tomem, copymem uintptr
    if uintptr(tolen) > uintptr(fromlen) {
        tomem, overflow = math.MulUintptr(et.Size_, uintptr(tolen))
        copymem = et.Size_ * uintptr(fromlen)  // 只拷贝 fromlen 个元素
    } else {
        tomem = et.Size_ * uintptr(tolen)
        copymem = tomem  // 目标更小,全部拷贝
    }

    var to unsafe.Pointer
    if !et.Pointers() {
        // 元素无指针:不需要 GC 扫描
        to = mallocgc(tomem, nil, false)
        if copymem < tomem {
            // 多余部分清零
            memclrNoHeapPointers(add(to, copymem), tomem-copymem)
        }
    } else {
        // 元素有指针:需要 GC 扫描
        to = mallocgc(tomem, et, true)  // true = 零初始化
    }

    memmove(to, from, copymem)  // 拷贝旧数据
    return to
}

2.3 growslice------扩容核心算法

源码位置:runtime/slice.go:126

这是 slice 最核心的函数,决定了 append 时的扩容策略:

go 复制代码
func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice {
    oldLen := newLen - num  // 原始长度

    // ★ 零大小元素的特殊处理
    if et.Size_ == 0 {
        // append 不应创建 nil 指针但非零 len 的 slice
        return slice{unsafe.Pointer(&zerobase), newLen, newLen}
    }

    // ★★★ 核心扩容策略 ★★★
    newcap := nextslicecap(newLen, oldCap)

    // ★ 内存对齐优化(根据元素大小分4种情况)
    var overflow bool
    var lenmem, newlenmem, capmem uintptr
    noscan := !et.Pointers()

    switch {
    case et.Size_ == 1:
        // byte 类型:无需乘法
        lenmem = uintptr(oldLen)
        newlenmem = uintptr(newLen)
        capmem = roundupsize(uintptr(newcap), noscan)  // ★ 对齐到 size class
        newcap = int(capmem)                            // newcap 可能因对齐而增大

    case et.Size_ == goarch.PtrSize:
        // 指针大小(8字节 on 64-bit):用位移代替乘除
        lenmem = uintptr(oldLen) * goarch.PtrSize
        newlenmem = uintptr(newLen) * goarch.PtrSize
        capmem = roundupsize(uintptr(newcap)*goarch.PtrSize, noscan)
        newcap = int(capmem / goarch.PtrSize)

    case isPowerOfTwo(et.Size_):
        // 2的幂次大小:用位移代替乘除
        var shift uintptr
        shift = uintptr(sys.TrailingZeros64(uint64(et.Size_))) & 63
        lenmem = uintptr(oldLen) << shift
        newlenmem = uintptr(newLen) << shift
        capmem = roundupsize(uintptr(newcap)<<shift, noscan)
        newcap = int(capmem >> shift)
        capmem = uintptr(newcap) << shift

    default:
        // 通用情况:乘法
        lenmem = uintptr(oldLen) * et.Size_
        newlenmem = uintptr(newLen) * et.Size_
        capmem, overflow = math.MulUintptr(et.Size_, uintptr(newcap))
        capmem = roundupsize(capmem, noscan)
        newcap = int(capmem / et.Size_)
        capmem = uintptr(newcap) * et.Size_
    }

    // ★ 分配新底层数组
    var p unsafe.Pointer
    if !et.Pointers() {
        p = mallocgc(capmem, nil, false)             // 无需 GC 扫描
        memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)  // 清零多余部分
    } else {
        p = mallocgc(capmem, et, true)               // 需要 GC 扫描 + 零初始化
    }
    // ★ 拷贝旧数据到新数组
    memmove(p, oldPtr, lenmem)

    return slice{p, newLen, newcap}
}

2.4 nextslicecap------扩容策略详解

源码位置:runtime/slice.go:231

go 复制代码
func nextslicecap(newLen, oldCap int) int {
    newcap := oldCap
    doublecap := newcap + newcap   // 2 * oldCap

    // 规则1: 如果新长度 > 2倍旧容量 → 直接用新长度
    if newLen > doublecap {
        return newLen
    }

    // 规则2: 旧容量 < 256 → 2倍增长
    const threshold = 256
    if oldCap < threshold {
        return doublecap
    }

    // 规则3: 旧容量 ≥ 256 → 1.25倍增长(平滑过渡)
    for {
        // newcap += (newcap + 3*threshold) / 4
        // 等价于: newcap = newcap * 1.25 + 192(近似)
        newcap += (newcap + 3*threshold) >> 2

        if uint(newcap) >= uint(newLen) {
            break
        }
    }

    // 溢出保护
    if newcap <= 0 {
        return newLen
    }
    return newcap
}

扩容策略三规则总结

复制代码
规则1: newLen > 2*oldCap     → newcap = newLen     (一次性分配足够)
规则2: oldCap < 256          → newcap = 2*oldCap   (小切片翻倍)
规则3: oldCap ≥ 256          → newcap ≈ 1.25*oldCap(大切片1.25倍)

过渡示例:
  oldCap=128, newLen=200 → 200 > 256? No → 128 < 256? Yes → newcap=256 (2x)
  oldCap=256, newLen=300 → 300 > 512? No → 256 < 256? No  → newcap=256+(256+768)/4=256+256=512
  oldCap=512, newLen=600 → 600 > 1024? No → 512 < 256? No → 512+(512+768)/4=512+320=832

#mermaid-svg-4Fvmnxl47fCenh5m{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4Fvmnxl47fCenh5m .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4Fvmnxl47fCenh5m .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4Fvmnxl47fCenh5m .error-icon{fill:#552222;}#mermaid-svg-4Fvmnxl47fCenh5m .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4Fvmnxl47fCenh5m .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4Fvmnxl47fCenh5m .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4Fvmnxl47fCenh5m .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4Fvmnxl47fCenh5m .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4Fvmnxl47fCenh5m .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4Fvmnxl47fCenh5m .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4Fvmnxl47fCenh5m .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4Fvmnxl47fCenh5m .marker.cross{stroke:#333333;}#mermaid-svg-4Fvmnxl47fCenh5m svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4Fvmnxl47fCenh5m p{margin:0;}#mermaid-svg-4Fvmnxl47fCenh5m .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4Fvmnxl47fCenh5m .cluster-label text{fill:#333;}#mermaid-svg-4Fvmnxl47fCenh5m .cluster-label span{color:#333;}#mermaid-svg-4Fvmnxl47fCenh5m .cluster-label span p{background-color:transparent;}#mermaid-svg-4Fvmnxl47fCenh5m .label text,#mermaid-svg-4Fvmnxl47fCenh5m span{fill:#333;color:#333;}#mermaid-svg-4Fvmnxl47fCenh5m .node rect,#mermaid-svg-4Fvmnxl47fCenh5m .node circle,#mermaid-svg-4Fvmnxl47fCenh5m .node ellipse,#mermaid-svg-4Fvmnxl47fCenh5m .node polygon,#mermaid-svg-4Fvmnxl47fCenh5m .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4Fvmnxl47fCenh5m .rough-node .label text,#mermaid-svg-4Fvmnxl47fCenh5m .node .label text,#mermaid-svg-4Fvmnxl47fCenh5m .image-shape .label,#mermaid-svg-4Fvmnxl47fCenh5m .icon-shape .label{text-anchor:middle;}#mermaid-svg-4Fvmnxl47fCenh5m .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4Fvmnxl47fCenh5m .rough-node .label,#mermaid-svg-4Fvmnxl47fCenh5m .node .label,#mermaid-svg-4Fvmnxl47fCenh5m .image-shape .label,#mermaid-svg-4Fvmnxl47fCenh5m .icon-shape .label{text-align:center;}#mermaid-svg-4Fvmnxl47fCenh5m .node.clickable{cursor:pointer;}#mermaid-svg-4Fvmnxl47fCenh5m .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4Fvmnxl47fCenh5m .arrowheadPath{fill:#333333;}#mermaid-svg-4Fvmnxl47fCenh5m .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4Fvmnxl47fCenh5m .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4Fvmnxl47fCenh5m .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4Fvmnxl47fCenh5m .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4Fvmnxl47fCenh5m .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4Fvmnxl47fCenh5m .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4Fvmnxl47fCenh5m .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4Fvmnxl47fCenh5m .cluster text{fill:#333;}#mermaid-svg-4Fvmnxl47fCenh5m .cluster span{color:#333;}#mermaid-svg-4Fvmnxl47fCenh5m div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4Fvmnxl47fCenh5m .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4Fvmnxl47fCenh5m rect.text{fill:none;stroke-width:0;}#mermaid-svg-4Fvmnxl47fCenh5m .icon-shape,#mermaid-svg-4Fvmnxl47fCenh5m .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4Fvmnxl47fCenh5m .icon-shape p,#mermaid-svg-4Fvmnxl47fCenh5m .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4Fvmnxl47fCenh5m .icon-shape .label rect,#mermaid-svg-4Fvmnxl47fCenh5m .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4Fvmnxl47fCenh5m .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4Fvmnxl47fCenh5m .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4Fvmnxl47fCenh5m :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 扩容策略
128→256

64→128
256→512→832

512→832→1184
容量跳跃
oldCap < 256

2x 增长
快速翻倍
oldCap ≥ 256

≈1.25x 增长
渐进增长
newLen > 2×oldCap

直接用 newLen
一次性满足

roundupsize------内存对齐到 size class

go 复制代码
// roundupsize 将申请大小向上对齐到 mallocgc 的 size class
// 这可能导致实际分配的 cap 比计算值更大
//
// 例: []int, 计算出 newcap=10, capmem=80
//     roundupsize(80, noscan=true) → 可能对齐到 96 (下一个 size class)
//     实际 newcap = 96/8 = 12
//
// 这就是为什么 make([]int, 10) 的 cap 可能大于 10 的原因

2.5 append 完整执行流程

编译器将 append 翻译为以下步骤:

复制代码
源码: s = append(s, x)

编译器生成的伪代码:

1. 如果 cap > len:
   // 有空间,直接写入
   s[len] = x
   s.len = len + 1
   
2. 如果 cap <= len:
   // 需要扩容
   newSlice := growslice(s.array, len+1, cap, 1, elemType)
   // growslice: 分配新数组 + 拷贝旧数据
   newSlice.array[len] = x      // 在新数组中写入
   newSlice.len = len + 1
   s = newSlice                 // 更新 slice header

3. 多元素 append: s = append(s, x, y, z)
   // 同理,但 num=3

#mermaid-svg-a67LUFq83f0pen9q{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a67LUFq83f0pen9q .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a67LUFq83f0pen9q .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a67LUFq83f0pen9q .error-icon{fill:#552222;}#mermaid-svg-a67LUFq83f0pen9q .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a67LUFq83f0pen9q .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a67LUFq83f0pen9q .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a67LUFq83f0pen9q .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a67LUFq83f0pen9q .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a67LUFq83f0pen9q .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a67LUFq83f0pen9q .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a67LUFq83f0pen9q .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a67LUFq83f0pen9q .marker.cross{stroke:#333333;}#mermaid-svg-a67LUFq83f0pen9q svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a67LUFq83f0pen9q p{margin:0;}#mermaid-svg-a67LUFq83f0pen9q .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-a67LUFq83f0pen9q .cluster-label text{fill:#333;}#mermaid-svg-a67LUFq83f0pen9q .cluster-label span{color:#333;}#mermaid-svg-a67LUFq83f0pen9q .cluster-label span p{background-color:transparent;}#mermaid-svg-a67LUFq83f0pen9q .label text,#mermaid-svg-a67LUFq83f0pen9q span{fill:#333;color:#333;}#mermaid-svg-a67LUFq83f0pen9q .node rect,#mermaid-svg-a67LUFq83f0pen9q .node circle,#mermaid-svg-a67LUFq83f0pen9q .node ellipse,#mermaid-svg-a67LUFq83f0pen9q .node polygon,#mermaid-svg-a67LUFq83f0pen9q .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-a67LUFq83f0pen9q .rough-node .label text,#mermaid-svg-a67LUFq83f0pen9q .node .label text,#mermaid-svg-a67LUFq83f0pen9q .image-shape .label,#mermaid-svg-a67LUFq83f0pen9q .icon-shape .label{text-anchor:middle;}#mermaid-svg-a67LUFq83f0pen9q .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a67LUFq83f0pen9q .rough-node .label,#mermaid-svg-a67LUFq83f0pen9q .node .label,#mermaid-svg-a67LUFq83f0pen9q .image-shape .label,#mermaid-svg-a67LUFq83f0pen9q .icon-shape .label{text-align:center;}#mermaid-svg-a67LUFq83f0pen9q .node.clickable{cursor:pointer;}#mermaid-svg-a67LUFq83f0pen9q .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-a67LUFq83f0pen9q .arrowheadPath{fill:#333333;}#mermaid-svg-a67LUFq83f0pen9q .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-a67LUFq83f0pen9q .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-a67LUFq83f0pen9q .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a67LUFq83f0pen9q .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-a67LUFq83f0pen9q .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a67LUFq83f0pen9q .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-a67LUFq83f0pen9q .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-a67LUFq83f0pen9q .cluster text{fill:#333;}#mermaid-svg-a67LUFq83f0pen9q .cluster span{color:#333;}#mermaid-svg-a67LUFq83f0pen9q div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a67LUFq83f0pen9q .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-a67LUFq83f0pen9q rect.text{fill:none;stroke-width:0;}#mermaid-svg-a67LUFq83f0pen9q .icon-shape,#mermaid-svg-a67LUFq83f0pen9q .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a67LUFq83f0pen9q .icon-shape p,#mermaid-svg-a67LUFq83f0pen9q .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-a67LUFq83f0pen9q .icon-shape .label rect,#mermaid-svg-a67LUFq83f0pen9q .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a67LUFq83f0pen9q .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a67LUFq83f0pen9q .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a67LUFq83f0pen9q :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Yes
No
s = append(s, elem)
len < cap?
直接写入

s.arraylen = elem

s.len++

★ 不分配内存
growslice 扩容
nextslicecap 计算新容量
roundupsize 内存对齐
mallocgc 分配新数组
memmove 拷贝旧数据
写入新元素

newArraynewLen-1 = elem
更新 slice header

array=newArray, len=newLen, cap=newCap
★ 旧数组可能被 GC 回收

(如果没有其他引用)

2.6 切片表达式------si:j 和 si:j:k

编译器对切片表达式的处理:

复制代码
s[i:j]      → slice{array: s.array + i*elemsize, len: j-i, cap: cap(s)-i}
s[i:j:k]    → slice{array: s.array + i*elemsize, len: j-i, cap: k-i}

例: s = []int{0,1,2,3,4,5}, len=6, cap=6
s[1:4]      → array=s.array+8, len=3, cap=5  [1,2,3]
s[1:4:5]    → array=s.array+8, len=3, cap=4  [1,2,3]  限制cap=4
s[:3]       → array=s.array,   len=3, cap=6  [0,1,2]
s[2:]       → array=s.array+16, len=4, cap=4  [2,3,4,5]

原 slice:  [0][1][2][3][4][5]
           ↑array
           │←── len=6 ──→│
           │←────── cap=6 ──────→│

s[1:4]:         [1][2][3][4][5]
                ↑s.array+8
                │← len=3 →│
                │←── cap=5 ──────→│

s[1:4:5]:       [1][2][3][4][5]
                ↑s.array+8
                │← len=3 →│
                │← cap=4 →│
                
                ★ 三索引切片限制了 cap
                ★ 防止 append 覆盖后续元素

2.7 copy 底层实现

源码位置:runtime/slice.go:310

go 复制代码
func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {
    if fromLen == 0 || toLen == 0 { return 0 }

    n := fromLen
    if toLen < n { n = toLen }  // 拷贝 min(fromLen, toLen) 个

    if width == 0 { return n }  // 零大小元素

    size := uintptr(n) * width

    if size == 1 {
        // ★ 1字节的优化:直接赋值
        *(*byte)(toPtr) = *(*byte)(fromPtr)
    } else {
        // ★ 通用:memmove
        memmove(toPtr, fromPtr, size)
    }
    return n
}

copy 的关键语义

go 复制代码
// copy 返回实际拷贝的元素数 = min(len(dst), len(src))
n := copy(dst, src)

// 源和目标可以重叠(底层是 memmove 不是 memcpy)
// copy 保证了即使 src 和 dst 有重叠区域,结果也是正确的

3 示例代码逐行解析

3.1 声明与初始化

go 复制代码
var s []int
// [编译器] s = slice{array: nil, len: 0, cap: 0}
// s == nil → true
// len(s) → 0
// cap(s) → 0

s = make([]int, 3)
// [编译器] 调用 makeslice(int类型, 3, 3)
// [运行时] mallocgc(3*8, int类型, true) → 返回 24 字节数组
//          s = slice{array: 指针, len: 3, cap: 3}

s = make([]int, 3, 10)
// [编译器] 调用 makeslice(int类型, 3, 10)
// [运行时] mallocgc(10*8, int类型, true) → 返回 80 字节数组
//          s = slice{array: 指针, len: 3, cap: 10}
//          s[0..2] = 0 (零初始化)
//          s[3..9] 已分配但不可直接访问

s := []int{1, 2, 3}
// [编译器] 在只读数据段生成数组 [1,2,3]
//          然后拷贝到堆上(逃逸分析决定)
//          s = slice{array: 堆数组, len: 3, cap: 3}

3.2 append 逐行解析

go 复制代码
s := make([]int, 0, 2)   // len=0, cap=2

s = append(s, 10)
// [编译器] 生成:
//   len = 0, cap = 2, len < cap → 有空间
//   s.array[0] = 10    // 直接写入
//   s.len = 1          // 更新长度
//   结果: s=[10], len=1, cap=2 ✅ 无扩容

s = append(s, 20)
// len = 1, cap = 2, len < cap → 有空间
// s.array[1] = 20
// s.len = 2
// 结果: s=[10,20], len=2, cap=2 ✅ 无扩容

s = append(s, 30)
// len = 2, cap = 2, len == cap → ★ 触发扩容!
// [编译器] 调用 growslice(s.array, 3, 2, 1, int类型)
//   oldLen = 3-1 = 2
//   newcap = nextslicecap(3, 2):
//     doublecap = 4, 3 > 4? No
//     oldCap(2) < 256? Yes → newcap = 4
//   capmem = roundupsize(4*8, noscan) = roundupsize(32, true)
//          → 可能对齐到 32(已经是 size class)
//   mallocgc(32, nil, false) → 分配新数组 32 字节
//   memmove(新数组, 旧数组, 16) → 拷贝 [10, 20]
//   新数组[2] = 30(由调用者写入)
//   s = slice{array: 新指针, len: 3, cap: 4}
//   ★ 旧数组(16字节)等待 GC 回收

s = append(s, 40, 50)
// len=3, cap=4, 需要2个空间, 但 cap-len=1 < 2 → ★ 扩容
// growslice(s.array, 5, 4, 2, int类型)
//   newcap = nextslicecap(5, 4):
//     doublecap = 8, 5 > 8? No
//     oldCap(4) < 256? Yes → newcap = 8
//   capmem = roundupsize(8*8) = 64
//   mallocgc(64, nil, false)
//   memmove 拷贝 [10,20,30]
//   新数组[3]=40, [4]=50
//   s = slice{array: 新指针, len: 5, cap: 8}

3.3 切片共享底层数组------最经典陷阱

go 复制代码
arr := [5]int{10, 20, 30, 40, 50}
// 底层数组: [10, 20, 30, 40, 50]

s1 := arr[1:3]   // s1=[20,30], len=2, cap=4
s2 := arr[2:4]   // s2=[30,40], len=2, cap=3

// ★ s1 和 s2 共享同一个底层数组!

s1[1] = 999
// 修改底层数组: [10, 20, 999, 40, 50]
// s2 也变了!s2=[999, 40]

// ★ 更隐蔽的陷阱:append 覆盖
s1 = append(s1, 100)
// s1 cap=4, len=2, 还有空间
// 底层数组: [10, 20, 999, 100, 50] ← s2[1] 从 40 变成了 100!
// s1 = [20, 999, 100], s2 = [999, 100]  ← s2 被意外修改!
复制代码
共享底层数组图示:

arr:  [10][20][30][40][50]
      ↑arr
      │←──── 5 ────→│

s1:       [20][30][40][50]
          ↑s1.array
          │←2→│←─4─→│
          len  cap

s2:           [30][40][50]
              ↑s2.array
              │←2→│←3→│
              len  cap

★ s1[2:4] 和 s2[0:2] 指向相同内存!
★ append(s1, 100) 会覆盖 s2 看到的数据!

3.4 nil slice vs 空 slice

go 复制代码
var s1 []int           // nil slice
s2 := []int{}          // 空 slice(非nil)
s3 := make([]int, 0)   // 空 slice(非nil)

// s1: slice{array: nil,      len: 0, cap: 0}  → s1 == nil → true
// s2: slice{array: &zerobase, len: 0, cap: 0} → s2 == nil → false
// s3: slice{array: 指针,      len: 0, cap: 0} → s3 == nil → false

// ★ 行为差异:
// - JSON 编码: nil slice → null, 空 slice → []
// - reflect: nil slice 的 Value.IsNil() = true
// - 其他操作 (len/cap/append/for range) 行为完全相同

// ★ 最佳实践:
// 如果要区分"无数据"和"空集合",用 nil slice 表示"无数据"

4 完整使用示例合集

4.1 基础增删改查

go 复制代码
package main

import "fmt"

func main() {
    // 创建
    s := make([]int, 0, 10)

    // 增(append)
    s = append(s, 1, 2, 3)       // s=[1,2,3]
    s = append(s, 4)             // s=[1,2,3,4]

    // 批量追加
    other := []int{5, 6, 7}
    s = append(s, other...)      // s=[1,2,3,4,5,6,7]

    // 改
    s[0] = 100                    // s=[100,2,3,4,5,6,7]

    // 删(删除索引 i=3)
    i := 3
    s = append(s[:i], s[i+1:]...) // s=[100,2,3,5,6,7]

    // 插入(在索引 i=2 处插入 999)
    s = append(s[:2], append([]int{999}, s[2:]...)...)
    // s=[100,2,999,3,5,6,7]

    // 查
    target := 999
    for idx, v := range s {
        if v == target {
            fmt.Printf("found %d at index %d\n", v, idx)
        }
    }

    fmt.Println(s)
}

4.2 删除元素的三种方式

go 复制代码
// 方式1: 保持顺序(慢,O(n))
s = append(s[:i], s[i+1:]...)

// 方式2: 不保持顺序(快,O(1))
s[i] = s[len(s)-1]
s = s[:len(s)-1]

// 方式3: Go 1.21+ 使用 slices.Delete
s = slices.Delete(s, i, i+1)  // 保持顺序

4.3 结构体切片

go 复制代码
type Item struct {
    Name  string
    Price float64
}

items := []Item{
    {"Apple", 1.5},
    {"Banana", 0.8},
}

// 修改字段
items[0].Price = 2.0  // ✅ 直接修改

// append
items = append(items, Item{"Cherry", 3.0})

4.4 二维切片

go 复制代码
// 创建 m×n 的二维切片
m, n := 3, 4
grid := make([][]int, m)         // 外层
for i := range grid {
    grid[i] = make([]int, n)     // 内层
}

// 或者共享底层数组(内存连续,缓存友好)
data := make([]int, m*n)         // 一块连续内存
grid := make([][]int, m)
for i := range grid {
    grid[i] = data[i*n : (i+1)*n]  // 切片引用同一段内存
}

4.5 切片去重

go 复制代码
func dedup(s []string) []string {
    seen := make(map[string]bool)
    result := s[:0]  // ★ 复用底层数组,零分配
    for _, v := range s {
        if !seen[v] {
            seen[v] = true
            result = append(result, v)
        }
    }
    return result
}

5 经典问题与优化

5.1 append 后原 slice 的数据变化

go 复制代码
s := make([]int, 3, 5)   // [0,0,0], len=3, cap=5
s[0], s[1], s[2] = 1, 2, 3

s2 := append(s, 4)        // 未扩容,写入 s.array[3]=4
// s  = [1,2,3]     len=3, cap=5
// s2 = [1,2,3,4]   len=4, cap=5
// ★ s 和 s2 共享底层数组!
// ★ s.array[3] 实际已被写入 4,但 s.len=3 所以 s "看不到"

s2[0] = 100
// ★ s[0] 也变成了 100!共享底层数组!

s2 = append(s2, 5, 6, 7)  // 触发扩容
// s2 指向新数组,不再与 s 共享
// s 仍然指向旧数组

#mermaid-svg-q9QwtpNgiwPm06tZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-q9QwtpNgiwPm06tZ .error-icon{fill:#552222;}#mermaid-svg-q9QwtpNgiwPm06tZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-q9QwtpNgiwPm06tZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-q9QwtpNgiwPm06tZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-q9QwtpNgiwPm06tZ .marker.cross{stroke:#333333;}#mermaid-svg-q9QwtpNgiwPm06tZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-q9QwtpNgiwPm06tZ p{margin:0;}#mermaid-svg-q9QwtpNgiwPm06tZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-q9QwtpNgiwPm06tZ .cluster-label text{fill:#333;}#mermaid-svg-q9QwtpNgiwPm06tZ .cluster-label span{color:#333;}#mermaid-svg-q9QwtpNgiwPm06tZ .cluster-label span p{background-color:transparent;}#mermaid-svg-q9QwtpNgiwPm06tZ .label text,#mermaid-svg-q9QwtpNgiwPm06tZ span{fill:#333;color:#333;}#mermaid-svg-q9QwtpNgiwPm06tZ .node rect,#mermaid-svg-q9QwtpNgiwPm06tZ .node circle,#mermaid-svg-q9QwtpNgiwPm06tZ .node ellipse,#mermaid-svg-q9QwtpNgiwPm06tZ .node polygon,#mermaid-svg-q9QwtpNgiwPm06tZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-q9QwtpNgiwPm06tZ .rough-node .label text,#mermaid-svg-q9QwtpNgiwPm06tZ .node .label text,#mermaid-svg-q9QwtpNgiwPm06tZ .image-shape .label,#mermaid-svg-q9QwtpNgiwPm06tZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-q9QwtpNgiwPm06tZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-q9QwtpNgiwPm06tZ .rough-node .label,#mermaid-svg-q9QwtpNgiwPm06tZ .node .label,#mermaid-svg-q9QwtpNgiwPm06tZ .image-shape .label,#mermaid-svg-q9QwtpNgiwPm06tZ .icon-shape .label{text-align:center;}#mermaid-svg-q9QwtpNgiwPm06tZ .node.clickable{cursor:pointer;}#mermaid-svg-q9QwtpNgiwPm06tZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-q9QwtpNgiwPm06tZ .arrowheadPath{fill:#333333;}#mermaid-svg-q9QwtpNgiwPm06tZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-q9QwtpNgiwPm06tZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-q9QwtpNgiwPm06tZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-q9QwtpNgiwPm06tZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-q9QwtpNgiwPm06tZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-q9QwtpNgiwPm06tZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-q9QwtpNgiwPm06tZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-q9QwtpNgiwPm06tZ .cluster text{fill:#333;}#mermaid-svg-q9QwtpNgiwPm06tZ .cluster span{color:#333;}#mermaid-svg-q9QwtpNgiwPm06tZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-q9QwtpNgiwPm06tZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-q9QwtpNgiwPm06tZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-q9QwtpNgiwPm06tZ .icon-shape,#mermaid-svg-q9QwtpNgiwPm06tZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-q9QwtpNgiwPm06tZ .icon-shape p,#mermaid-svg-q9QwtpNgiwPm06tZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-q9QwtpNgiwPm06tZ .icon-shape .label rect,#mermaid-svg-q9QwtpNgiwPm06tZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-q9QwtpNgiwPm06tZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-q9QwtpNgiwPm06tZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-q9QwtpNgiwPm06tZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 扩容后分离
append 前后共享
再次append

触发扩容
扩容
s: len=3, cap=5

1,2,3,_,_

s2: len=4, cap=5

1,2,3,4,_

s: 旧数组

1,2,3,4,_

s2: 新数组

1,2,3,4,5,6,7,_

5.2 大量 append 的性能优化------预分配

go 复制代码
// ❌ 不预分配:多次扩容,多次拷贝
var s []int
for i := 0; i < 10000; i++ {
    s = append(s, i)  // 可能扩容 ~14 次
}

// ✅ 预分配:一次分配,无拷贝
s := make([]int, 0, 10000)
for i := 0; i < 10000; i++ {
    s = append(s, i)  // 从不扩容
}

// ✅ 更好:直接用长度
s := make([]int, 10000)
for i := range s {
    s[i] = i
}

扩容次数对比

复制代码
不预分配 append 10000 个 int:
  0→1→2→4→8→16→32→64→128→256→512→1024→2048→4096→8192→12288
  扩容 15 次,拷贝 1+2+4+...+8192 = 16383 个元素

预分配 make([]int, 0, 10000):
  扩容 0 次,拷贝 0 个元素

5.3 切片内存泄漏

go 复制代码
// ❌ 内存泄漏:大切片切小后,底层数组仍持有全部数据
func leak() []int {
    big := make([]int, 1000000)  // 8MB
    // ... 填充数据 ...
    return big[:10]               // 只返回前10个,但底层 8MB 不会被 GC!
}

// ✅ 修复:拷贝到新切片
func noLeak() []int {
    big := make([]int, 1000000)
    // ... 填充数据 ...
    result := make([]int, 10)
    copy(result, big[:10])
    return result   // big 可以被 GC 回收
}

5.4 三索引切片限制容量

go 复制代码
arr := [10]int{0,1,2,3,4,5,6,7,8,9}

s := arr[2:5:5]   // len=3, cap=3(限制 cap=5-2=3)
// ★ cap 被限制为 3,而不是 8

s = append(s, 100)  // len=3, cap=3 → 必须扩容!
// ★ 扩容后 s 指向新数组,不再影响 arr

// 如果不用三索引:
s2 := arr[2:5]    // len=3, cap=8
s2 = append(s2, 100)  // 不扩容!直接写入 arr[5]=100
// ★ 意外修改了 arr!

5.5 slice 不可比较的原因

go 复制代码
// s1 == s2 → 编译错误!
// 原因:
// 1. slice 是引用类型,== 比较的是 header 还是内容?语义不明确
// 2. 如果比较内容,深比较 O(n),不符合 == 的 O(1) 预期
// 3. slice 可能有共享底层数组,比较语义复杂

// ✅ 正确的比较方式
func sliceEqual[T comparable](a, b []T) bool {
    if len(a) != len(b) { return false }
    for i := range a {
        if a[i] != b[i] { return false }
    }
    return true
}

// Go 1.21+: 使用 slices.Equal
slices.Equal(s1, s2)

5.6 切片表达式越界 panic 规则

go 复制代码
s := make([]int, 5, 10)

// ✅ 合法
_ = s[0:5]    // 0 ≤ low ≤ high ≤ cap
_ = s[2:8]    // high 可以超过 len,但不超过 cap
_ = s[:5]     // 省略 low = 0
_ = s[2:]     // 省略 high = len

// ❌ panic
_ = s[0:11]   // high > cap → panic: slice bounds out of range
_ = s[6:8]    // low > len → panic: slice bounds out of range
_ = s[3:2]    // high < low → panic: slice bounds out of range

6 总结:Slice 核心知识图谱

#mermaid-svg-yEIKbPzPkVVtI4mH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yEIKbPzPkVVtI4mH .error-icon{fill:#552222;}#mermaid-svg-yEIKbPzPkVVtI4mH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yEIKbPzPkVVtI4mH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yEIKbPzPkVVtI4mH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yEIKbPzPkVVtI4mH .marker.cross{stroke:#333333;}#mermaid-svg-yEIKbPzPkVVtI4mH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yEIKbPzPkVVtI4mH p{margin:0;}#mermaid-svg-yEIKbPzPkVVtI4mH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yEIKbPzPkVVtI4mH .cluster-label text{fill:#333;}#mermaid-svg-yEIKbPzPkVVtI4mH .cluster-label span{color:#333;}#mermaid-svg-yEIKbPzPkVVtI4mH .cluster-label span p{background-color:transparent;}#mermaid-svg-yEIKbPzPkVVtI4mH .label text,#mermaid-svg-yEIKbPzPkVVtI4mH span{fill:#333;color:#333;}#mermaid-svg-yEIKbPzPkVVtI4mH .node rect,#mermaid-svg-yEIKbPzPkVVtI4mH .node circle,#mermaid-svg-yEIKbPzPkVVtI4mH .node ellipse,#mermaid-svg-yEIKbPzPkVVtI4mH .node polygon,#mermaid-svg-yEIKbPzPkVVtI4mH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yEIKbPzPkVVtI4mH .rough-node .label text,#mermaid-svg-yEIKbPzPkVVtI4mH .node .label text,#mermaid-svg-yEIKbPzPkVVtI4mH .image-shape .label,#mermaid-svg-yEIKbPzPkVVtI4mH .icon-shape .label{text-anchor:middle;}#mermaid-svg-yEIKbPzPkVVtI4mH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yEIKbPzPkVVtI4mH .rough-node .label,#mermaid-svg-yEIKbPzPkVVtI4mH .node .label,#mermaid-svg-yEIKbPzPkVVtI4mH .image-shape .label,#mermaid-svg-yEIKbPzPkVVtI4mH .icon-shape .label{text-align:center;}#mermaid-svg-yEIKbPzPkVVtI4mH .node.clickable{cursor:pointer;}#mermaid-svg-yEIKbPzPkVVtI4mH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yEIKbPzPkVVtI4mH .arrowheadPath{fill:#333333;}#mermaid-svg-yEIKbPzPkVVtI4mH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yEIKbPzPkVVtI4mH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yEIKbPzPkVVtI4mH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yEIKbPzPkVVtI4mH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yEIKbPzPkVVtI4mH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yEIKbPzPkVVtI4mH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yEIKbPzPkVVtI4mH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yEIKbPzPkVVtI4mH .cluster text{fill:#333;}#mermaid-svg-yEIKbPzPkVVtI4mH .cluster span{color:#333;}#mermaid-svg-yEIKbPzPkVVtI4mH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yEIKbPzPkVVtI4mH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yEIKbPzPkVVtI4mH rect.text{fill:none;stroke-width:0;}#mermaid-svg-yEIKbPzPkVVtI4mH .icon-shape,#mermaid-svg-yEIKbPzPkVVtI4mH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yEIKbPzPkVVtI4mH .icon-shape p,#mermaid-svg-yEIKbPzPkVVtI4mH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yEIKbPzPkVVtI4mH .icon-shape .label rect,#mermaid-svg-yEIKbPzPkVVtI4mH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yEIKbPzPkVVtI4mH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yEIKbPzPkVVtI4mH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yEIKbPzPkVVtI4mH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Slice 核心知识
slice header

array+len+cap=24B
创建

make/字面量/数组切片
扩容策略

<256: 2x

≥256: ≈1.25x
append

有空间直接写

无空间growslice
共享底层数组

切片是引用视图
三索引切片

限制cap防覆盖
内存泄漏

大切片切小未copy
nil vs 空

nil=无数据

空=零长度集合
copy

min len

memmove

slice 操作一图总结

复制代码
┌───────────────────────────────────────────────────────────┐
│                  Slice 操作速查                            │
├─────────────┬─────────────────────────────────────────────┤
│ 创建         │ make([]T, len, cap)  字面量  数组[:]        │
│ 追加         │ append(s, x...)      可能触发扩容           │
│ 删除(i)      │ append(s[:i], s[i+1:]...)  O(n)            │
│ 插入(i,v)    │ append(s[:i], append([]T{v}, s[i:]...)...) │
│ 复制         │ copy(dst, src)       min(len) 个           │
│ 切片         │ s[i:j]    s[i:j:k]   共享底层数组           │
│ 遍历         │ for i,v := range s                         │
│ 长度/容量     │ len(s) / cap(s)                            │
│ 零值         │ nil (array=nil, len=0, cap=0)              │
│ 比较         │ 只能与 nil 比较,内容比较用 slices.Equal     │
├─────────────┼─────────────────────────────────────────────┤
│ 扩容策略      │ oldCap < 256 → 2×                          │
│              │ oldCap ≥ 256 → ≈1.25×                      │
│              │ newLen > 2×oldCap → newLen                  │
│              │ 实际可能因 roundupsize 更大                   │
└─────────────┴─────────────────────────────────────────────┘

源码索引

文件 关键内容
runtime/slice.go:14 slice 结构体定义(array/len/cap)
runtime/slice.go:57 makeslice------创建切片内存分配
runtime/slice.go:28 makeslicecopy------append 触发的创建+拷贝
runtime/slice.go:126 growslice------扩容核心(分配新数组+拷贝)
runtime/slice.go:231 nextslicecap------扩容策略(2x/1.25x/newLen)
runtime/slice.go:310 slicecopy------copy 底层实现
runtime/slice.go:345 growsliceNoAlias------已知无别名的优化扩容
runtime/slice.go:415 growsliceBuf------栈缓冲区扩容优化
reflect/value.go:2701 SliceHeader(已废弃,改用 unsafe.Slice)
相关推荐
码云骑士2 小时前
09-Python模块导入机制-sys.path与循环导入的死锁式排查
开发语言·python
星恒随风2 小时前
C++ 模板初阶:从泛型编程、函数模板到类模板,一篇打通基础概念
开发语言·c++·笔记·学习
郝学胜-神的一滴2 小时前
Qt 高级开发 031:QListWidget图标布局实战
开发语言·c++·qt·程序人生·软件构建·用户界面
caimouse2 小时前
Reactos 第 8 章 结构化异常处理 — 8.4 软异常
服务器·开发语言·windows
艾莉丝努力练剑2 小时前
【Qt】界面优化:绘图API
linux·运维·开发语言·网络·qt·tcp/ip·udp
牛油果子哥q2 小时前
队列(Queue)深度精讲,先进先出原理、顺序/链式/循环队列、STL queue底层、栈队列互模拟与面试考点全解
开发语言·c++·面试
聆风吟º2 小时前
【Python编程日志】Python基础数据类型完整梳理
开发语言·python·数据类型
weixin_307779132 小时前
在 Azure 上构建数据库路由与异构整合层:原理、方案与最佳实践
数据库·人工智能·后端·云计算·azure
都说名字长不会被发现2 小时前
Spring Boot Starter 中间件账号密码加密方案设计与实现
java·spring boot·后端·中间件