wavelet init

This commit is contained in:
ryan
2026-06-18 15:24:48 +08:00
parent d6a7011885
commit 99738bbc17
714 changed files with 139987 additions and 0 deletions
@@ -0,0 +1,146 @@
# Go 切片内部原理
> **来源**:Effective Go
---
## 三项描述符
切片是一个运行时数据结构,包含三个组件:
- **指针**:第一个可访问元素的地址
- **长度**:元素数量(`len(s)`)
- **容量**:到底层数组末尾的最大元素数(`cap(s)`)
```go
arr := [5]int{10, 20, 30, 40, 50}
s := arr[1:4] // s = [20, 30, 40]
// 指针:&arr[1],长度:3,容量:4
```
`nil` 切片的三项均为零/nil。
---
## 切片引用底层数组
切片不存储数据 — 它们描述数组的一部分:
```go
data := [4]int{1, 2, 3, 4}
a := data[0:2] // [1, 2]
b := data[1:3] // [2, 3]
b[0] = 99
fmt.Println(a) // [1, 99] - 两者都看到变化
fmt.Println(data) // [1, 99, 3, 4]
```
---
## 切片运算符
`s[lo:hi]` 创建从索引 `lo` 到 `hi-1` 的切片:
```go
s := []int{0, 1, 2, 3, 4, 5}
s[2:4] // [2, 3]
s[:3] // [0, 1, 2]
s[3:] // [3, 4, 5]
```
三索引形式 `s[lo:hi:max]` 将容量限制为 `max-lo`。
---
## 为什么 append 必须返回切片
切片头是**按值传递**的。函数可以修改元素但无法改变调用者的切片头:
```go
func Append(slice, data []byte) []byte {
l := len(slice)
if l+len(data) > cap(slice) {
newSlice := make([]byte, (l+len(data))*2)
copy(newSlice, slice)
slice = newSlice // 只改变局部变量
}
slice = slice[0 : l+len(data)]
copy(slice[l:], data)
return slice // 调用者必须接收新的切片头
}
```
当发生重新分配时,`slice` 指向新数组。调用者的原始引用仍指向旧数组 — 返回使调用者能够更新其引用。
---
## copy 函数
`copy(dst, src)` 复制元素并返回复制的数量:
```go
src := []int{1, 2, 3, 4, 5}
dst := make([]int, 3)
n := copy(dst, src) // n=3, dst=[1,2,3]
```
正确处理重叠切片。复制 `min(len(dst), len(src))` 个元素 — 不会发生重新分配。
---
## 切片常见陷阱
### 1. 共享底层数组
```go
original := []int{1, 2, 3, 4, 5}
subset := original[1:3]
subset[0] = 99
fmt.Println(original) // [1, 99, 3, 4, 5] - 被修改了!
// 修复:创建独立副本
subset := make([]int, 2)
copy(subset, original[1:3])
```
### 2. append 可能重新分配也可能不
```go
a := make([]int, 3, 5) // len=3, cap=5
b := a[0:3]
a = append(a, 4) // 在容量内 - 仍然共享
a = append(a, 5, 6) // 超出容量 - 现在独立
```
### 3. 大底层数组导致内存泄漏
```go
// 不好:小切片将整个文件保留在内存中
func getHeader(file []byte) []byte { return file[:100] }
// 好:复制以释放大数组
func getHeader(file []byte) []byte {
header := make([]byte, 100)
copy(header, file)
return header
}
```
### 4. nil vs 空切片
```go
var nilSlice []int // nil, len=0, cap=0
emptySlice := []int{} // 非 nil, len=0, cap=0
// 两者在 len、cap、append、range 中表现相同
// 未初始化状态优先使用 nil
```
## 快速参考
| 操作 | 行为 |
|------|------|
| `s[lo:hi]` | 从 lo 到 hi-1 的切片 |
| `s[lo:hi:max]` | 容量限制为 max-lo 的切片 |
| `append(s, x...)` | 返回新切片;可能重新分配 |
| `copy(dst, src)` | 返回复制数量;不重新分配 |