Daily Study
更新: 10/6/2025 字数: 0 字 时长: 0 分钟
Daily Plan
#todo
- [ ]
闭包陷阱
从该语句出发:ans = append(ans, append([]int(nil), path...))
语句的含义是:将 path 切片的内容复制一份,并将这份副本作为一个新的元素添加到 ans(结果切片)中。
主要包括两个操作:
append([]int(nil),path...):把path的所有内容复制到新建的[]int(nil)切片上ans = append(ans , ):追加到ans数组中
这条语句的使用场景几乎都出现在递归或回溯算法中(比如路径查找、组合生成等),其中 path 是一个在整个递归过程中被重复使用和修改的工作切片。
如果不创建副本,而是直接将 path 添加到 ans 中,就会产生著名的 “切片闭包陷阱”:ans = append(ans, path)。由于 ans 中的元素和当前的 path 共享同一个底层数组,当你修改 path 时,ans 中存储的所有旧结果也会被一同修改!
详解一下其中的 []int(nil):
[]int:切片类型字面量:[]int本身是 Go 语言中表示int类型的切片 的类型字面量。(nil):零值nil是 Go 语言中许多引用类型(如指针、切片、映射、通道、函数和接口)的零值。[]int(nil):类型转换 (Type Conversion)
这整个表达式使用了 Go 的类型转换语法:T(V),其中 T 是目标类型,而 V 是要转换的值。 在这里:
- 目标类型 T 是
[]int(切片)。 - 值 V 是
nil(切片的零值)。
Go 语言允许将 nil 这个引用类型的零值显式地转换为任何引用类型(如切片、映射、指针等)。
虽然 []int(nil) 和 make([]int, 0) 都会创建一个长度和容量都为 0 的空切片,但它们在底层存储上略有不同:
| 表达式 | 底层指针 | 内存分配 | 优势 |
|---|---|---|---|
[]int(nil) | nil | 没有底层数组分配 | 最轻量级,通常用于函数返回值或比较。 |
make([]int, 0) | 非 nil | 有底层数组(虽然长度为 0) | 底层指针非 nil,有时更适合作为函数参数。 |
在您的原始代码 append([]int(nil), path...) 中,使用 []int(nil) 确保了 append 操作是从一个完全独立、零开销的切片开始构建副本。
