在 Go 语言里,...
跟在 slice 后面,是 “解包(unpack)”操作,它的作用是把一个切片的元素逐个展开,作为可变参数传入函数,而不是把整个切片当作一个单独的参数。
📌 典型场景:append
追加切片
s1 := []int{1, 2, 3}
s2 := []int{4, 5, 6}
// 如果直接 append(s1, s2) 会报错,因为 s2 是一个切片,不是单个元素
// 用 ... 解包,把 s2 的每个元素依次追加到 s1
s1 = append(s1, s2...)
fmt.Println(s1) // 输出: [1 2 3 4 5 6]
这里的 s2...
就是把 s2
展开成 4, 5, 6
三个独立的参数传给 append
。
📌 适用范围
...
这种解包语法只能用在函数调用的最后一个参数位置,并且该参数必须是可变参数(variadic parameter),例如:
func sum(nums ...int) int {
total := 0
for _, v := range nums {
total += v
}
return total
}
arr := []int{1, 2, 3}
fmt.Println(sum(arr...)) // 等价于 sum(1, 2, 3)
在 Go 里,严格意义上并没有一个和 ...
解包对称的“打包/合并”运算符。
所谓“合并”切片,通常是通过 append
或 copy
等函数来实现的,而不是用某个单独的语法符号。
🔹 常见的“合并”方式
1. 用 append
合并两个或多个切片
a := []int{1, 2, 3}
b := []int{4, 5, 6}
c := []int{7, 8}
// 合并 a 和 b
a = append(a, b...) // b... 是解包,把 b 的元素追加到 a
// 再合并 c
a = append(a, c...)
fmt.Println(a) // [1 2 3 4 5 6 7 8]
这里虽然用到了
...
,但它的作用是解包参数,合并的动作是由append
完成的。
2. 用 copy
先分配好目标切片,再拷贝
a := []int{1, 2, 3}
b := []int{4, 5, 6}
merged := make([]int, len(a)+len(b))
copy(merged, a)
copy(merged[len(a):], b)
fmt.Println(merged) // [1 2 3 4 5 6]
这种方式在需要精确控制内存分配时更高效,因为只分配一次底层数组。
3. 多个切片一次性合并
a := []int{1, 2}
b := []int{3, 4}
c := []int{5, 6}
merged := append(append(a, b...), c...)
fmt.Println(merged) // [1 2 3 4 5 6]
Go 没有像 Python 那样的
+
运算符直接拼接切片,必须显式调用append
。
在 Go 语言里,copy
是一个内置函数,专门用来将一个切片(slice)的元素复制到另一个切片。它的函数签名是:
func copy(dst, src []T) int
dst
:目标切片(要把数据复制到这里)src
:源切片(数据从这里来)- 返回值:实际复制的元素个数(取
len(dst)
和len(src)
的最小值)
🔹 基本用法
a := []int{1, 2, 3}
b := make([]int, 5) // 目标切片长度为 5
n := copy(b, a)
fmt.Println(b) // [1 2 3 0 0]
fmt.Println(n) // 3
这里 copy
会把 a
的前三个元素复制到 b
的前三个位置,剩下的保持原值。
🔹 部分复制
copy
可以配合切片表达式复制一部分:
src := []int{10, 20, 30, 40, 50}
dst := make([]int, 3)
copy(dst, src[2:]) // 从 src 的第 3 个元素开始复制
fmt.Println(dst) // [30 40 50]
🔹 特点与注意事项
- 不会自动扩容:
copy
只会在dst
已有的长度范围内复制,不会改变dst
的长度。 - 类型必须一致:
dst
和src
的元素类型必须相同。 - 可以重叠:
dst
和src
可以引用同一个底层数组(甚至有重叠区域),copy
会安全处理。 - 深浅拷贝:
- 对于基础类型元素,
copy
复制的是值(相当于深拷贝元素本身)。 - 对于引用类型元素(如切片、map、指针、结构体中含指针),
copy
复制的是引用地址(浅拷贝)。
- 对于基础类型元素,