数组、切片与集合
约 1127 字大约 4 分钟
2026-03-25
数组
数组是单一元素类型编号序列,元素的数量称为数组的长度(length),且长度是类型的一部分。元素在内存中排列紧密,访问效率极高
重要
- 数组在声明后长度不可改变
- 数组是值类型,赋值和传参会完整拷贝整个数组。如果函数的参数是数组类型,调用时会复制整个数组,可能导致性能问题。通常使用切片来代替数组,或使用指针来避免复制
数组声明
var array_name [quantity]Type
// 例如
var arr [5]int使用字面量初始化
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := [5]int{1, 2} // 未初始化的元素默认为 0自动推断长度
arr := [...]int{1, 2, 3, 4, 5}稀疏数组
// arr[0] = 1, arr[3] = 4, 其他元素默认为 0
arr := [5]int{0: 1, 3: 4}为数组元素赋值与其他语言类似,使用索引来进行访问和修改
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
arr[0] = 10
fmt.Println(arr)
fmt.Println(arr[1])
}切片
一个切片是对数组的连续的描述。它包含了一个指向底层数组的指针、长度和容量。与数组不同的是,切片是动态的,长度可变
重要
- 切片使用
[]T表示,数组是[n]T - 切片是引用类型,赋值和传参会复制切片结构体,但底层数组不会被复制。多个切片可以共享同一个底层数组,修改其中一个切片的元素会影响其他切片
make 创建切片
s1 := make([]int, 5) // len=5, cap=5
s2 := make([]int, 3, 10) // len=3, cap=10(预分配容量)字面量创建切片
s3 := []int{1, 2, 3, 4, 5} // len=5, cap=5每个切片在内存中实际是一个 slice header,大小固定为 24 字节(64位系统):
type slice struct {
array unsafe.Pointer // 指向底层数组的指针
len int // 当前元素个数(长度)
cap int // 底层数组可容纳的最大元素个数(容量)
}len 与 cap 的区别
len 表示的是当前切片元素的实际个数,cap 表示底层数组从切片起始位置开始还能容纳的最大元素格式。当 append 时,如果 len < cap,则直接在原有底层数组上追加;如果 len == cap,则 Go 会分配一个更大的新底层数组(通常按 2 倍或 1.25 倍扩容),然后拷贝元素
切片截取
package main
import "fmt"
func main() {
arr := [5]int{10, 20, 30, 40, 50}
// 左闭右开
s4 := arr[1:4] // 包含索引 1, 2, 3 的元素,s4 = [20, 30, 40]
s5 := arr[:3] // 包含索引 0, 1, 2 的元素,s5 = [10, 20, 30]
s6 := arr[2:] // 包含索引 2, 3, 4 的元素,s6 = [30, 40, 50]
fmt.Println(s4)
fmt.Println(s5)
fmt.Println(s6)
}集合
集合 Set 是一种无序、元素唯一的数据结构,Go 标准库没有内置集合类型,但可以使用 map 来实现集合的功能
社区公认的最佳实践是使用:map[T]struct{} 来模式
实现 Set
package set
type Set[T comparable] map[T]struct{}
func New[T comparable](items ...T) Set[T] {
// 使用 make 创建一个空的 map,初始容量为 items 的长度
s := make(Set[T], len(items))
for _, item := range items {
s.Add(item)
}
return s
}
func (s Set[T]) Add(item T) {
s[item] = struct{}{}
}
func (s Set[T]) Remove(item T) {
delete(s, item)
}
func (s Set[T]) Contains(item T) bool {
_, ok := s[item]
return ok
}
func (s Set[T]) Len() int {
return len(s)
}
func (s Set[T]) Clear() {
for k : range s {
delete(s, k)
}
}
func (s Set[T]) ToSlice() []T {
result := make([]T, 0, len(s))
for item := range s {
result = append(result, item)
}
return result
}
func (s Set[T]) Clone Set[T] {
clone := New[T]()
for item := range s {
clone.Add(item)
}
}使用
func main() {
fruits := set.New("apple", "banana", "apple", "orange") // 自动去重
fmt.Println(fruits.Contains("apple")) // true
fmt.Println(fruits.Len()) // 3
fruits.Remove("banana")
fmt.Println(fruits.ToSlice()) // ["apple", "orange"](顺序不固定)
}重要
当把 Set 定义为 map[T]struct{} 时:元素本身 变成了 map 的 key;value 是一个空的 struct 只是一个占位符,完全不重要
集合常用于需要快速查找、去重等场景
