#Go Slices
Slices are one of the most important data types in Go, providing dynamic array functionality. Slices are built on top of arrays but are more powerful, flexible, and commonly used than arrays.
#🎯 Slice Basics
#Slice Declaration and Initialization
package main
import "fmt"
func main() {
// 1. 声明切片(零值为 nil)
var slice1 []int
fmt.Printf("零值切片: %v, 长度: %d, 容量: %d, 是否为nil: %t\n",
slice1, len(slice1), cap(slice1), slice1 == nil)
// 2. 使用字面量创建切片
slice2 := []int{1, 2, 3, 4, 5}
fmt.Printf("字面量切片: %v, 长度: %d, 容量: %d\n",
slice2, len(slice2), cap(slice2))
// 3. 使用 make 创建切片
slice3 := make([]int, 5) // 长度和容量都是 5
slice4 := make([]int, 3, 10) // 长度 3,容量 10
fmt.Printf("make切片(5): %v, 长度: %d, 容量: %d\n",
slice3, len(slice3), cap(slice3))
fmt.Printf("make切片(3,10): %v, 长度: %d, 容量: %d\n",
slice4, len(slice4), cap(slice4))
// 4. 从数组创建切片
array := [6]int{10, 20, 30, 40, 50, 60}
slice5 := array[1:4] // 从索引1到3(不包括4)
slice6 := array[:3] // 从开始到索引2
slice7 := array[2:] // 从索引2到结束
slice8 := array[:] // 整个数组
fmt.Printf("原数组: %v\n", array)
fmt.Printf("slice5 [1:4]: %v\n", slice5)
fmt.Printf("slice6 [:3]: %v\n", slice6)
fmt.Printf("slice7 [2:]: %v\n", slice7)
fmt.Printf("slice8 [:]: %v\n", slice8)
}#Internal Structure of Slices
import "unsafe"
func main() {
// 切片的内部结构:指针、长度、容量
slice := []int{1, 2, 3, 4, 5}
fmt.Printf("切片: %v\n", slice)
fmt.Printf("长度: %d\n", len(slice))
fmt.Printf("容量: %d\n", cap(slice))
fmt.Printf("切片大小: %d 字节\n", unsafe.Sizeof(slice))
// 切片头信息
fmt.Printf("切片地址: %p\n", &slice)
fmt.Printf("底层数组地址: %p\n", &slice[0])
// 切片之间共享底层数组
slice1 := slice[1:4]
slice2 := slice[2:5]
fmt.Printf("\n切片共享:\n")
fmt.Printf("原切片: %v\n", slice)
fmt.Printf("slice1[1:4]: %v\n", slice1)
fmt.Printf("slice2[2:5]: %v\n", slice2)
// 修改 slice1 会影响其他切片
slice1[1] = 100
fmt.Printf("\n修改 slice1[1] 后:\n")
fmt.Printf("原切片: %v\n", slice)
fmt.Printf("slice1: %v\n", slice1)
fmt.Printf("slice2: %v\n", slice2)
}#➕ Slice Operations
#append Function
func main() {
// append 添加元素
var slice []int
fmt.Printf("初始切片: %v, 长度: %d, 容量: %d\n", slice, len(slice), cap(slice))
// 逐个添加元素
slice = append(slice, 1)
fmt.Printf("添加1: %v, 长度: %d, 容量: %d\n", slice, len(slice), cap(slice))
slice = append(slice, 2, 3, 4)
fmt.Printf("添加2,3,4: %v, 长度: %d, 容量: %d\n", slice, len(slice), cap(slice))
// 添加另一个切片
slice2 := []int{5, 6, 7}
slice = append(slice, slice2...) // 使用 ... 展开切片
fmt.Printf("添加另一个切片: %v, 长度: %d, 容量: %d\n", slice, len(slice), cap(slice))
// 容量增长演示
fmt.Println("\n容量增长演示:")
slice3 := make([]int, 0, 2)
for i := 0; i < 10; i++ {
slice3 = append(slice3, i)
fmt.Printf("添加%d: 长度=%d, 容量=%d\n", i, len(slice3), cap(slice3))
}
}#copy Function
func main() {
// copy 函数复制切片
source := []int{1, 2, 3, 4, 5}
// 创建目标切片
dest1 := make([]int, len(source))
dest2 := make([]int, 3) // 长度小于源切片
dest3 := make([]int, 7) // 长度大于源切片
// 复制切片
n1 := copy(dest1, source)
n2 := copy(dest2, source)
n3 := copy(dest3, source)
fmt.Printf("源切片: %v\n", source)
fmt.Printf("完整复制: %v (复制了%d个元素)\n", dest1, n1)
fmt.Printf("部分复制: %v (复制了%d个元素)\n", dest2, n2)
fmt.Printf("扩展复制: %v (复制了%d个元素)\n", dest3, n3)
// 修改原切片不影响复制的切片
source[0] = 100
fmt.Printf("\n修改源切片后:\n")
fmt.Printf("源切片: %v\n", source)
fmt.Printf("复制的切片: %v\n", dest1)
// 切片之间的复制
slice1 := []int{1, 2, 3}
slice2 := []int{4, 5, 6, 7, 8}
fmt.Printf("\n切片间复制:\n")
fmt.Printf("复制前: slice1=%v, slice2=%v\n", slice1, slice2)
copy(slice2[1:4], slice1) // 将 slice1 复制到 slice2 的中间位置
fmt.Printf("复制后: slice1=%v, slice2=%v\n", slice1, slice2)
}#Slice Slicing
func main() {
slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Printf("原切片: %v\n", slice)
// 基本切分
fmt.Printf("slice[2:7]: %v\n", slice[2:7])
fmt.Printf("slice[:5]: %v\n", slice[:5])
fmt.Printf("slice[3:]: %v\n", slice[3:])
fmt.Printf("slice[:]: %v\n", slice[:])
// 三参数切分:[start:end:cap]
sub1 := slice[2:5:7] // 从索引2到4,容量限制为7-2=5
fmt.Printf("slice[2:5:7]: %v, 长度: %d, 容量: %d\n",
sub1, len(sub1), cap(sub1))
// 切分的切片共享底层数组
sub2 := slice[1:6]
fmt.Printf("\n切分共享演示:\n")
fmt.Printf("原切片: %v\n", slice)
fmt.Printf("子切片: %v\n", sub2)
sub2[2] = 100
fmt.Printf("修改子切片后:\n")
fmt.Printf("原切片: %v\n", slice)
fmt.Printf("子切片: %v\n", sub2)
}#🔧 Advanced Slice Operations
#Slice Growth Mechanism
func main() {
// 观察切片扩容
fmt.Println("切片扩容机制:")
slice := make([]int, 0, 1)
for i := 0; i < 20; i++ {
oldCap := cap(slice)
slice = append(slice, i)
newCap := cap(slice)
if newCap != oldCap {
fmt.Printf("长度 %d: 容量从 %d 扩展到 %d (扩展比例: %.2f)\n",
len(slice), oldCap, newCap, float64(newCap)/float64(oldCap))
}
}
// 预分配容量的重要性
fmt.Println("\n性能对比:")
// 不预分配容量
slice1 := []int{}
for i := 0; i < 1000; i++ {
slice1 = append(slice1, i)
}
// 预分配容量
slice2 := make([]int, 0, 1000)
for i := 0; i < 1000; i++ {
slice2 = append(slice2, i)
}
fmt.Printf("不预分配: 最终容量 %d\n", cap(slice1))
fmt.Printf("预分配: 最终容量 %d\n", cap(slice2))
}#Slice Deletion Operations
func main() {
// 切片删除元素的各种方法
slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// 1. 删除第一个元素
fmt.Printf("原切片: %v\n", slice)
slice = slice[1:]
fmt.Printf("删除第一个元素: %v\n", slice)
// 重置切片
slice = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// 2. 删除最后一个元素
slice = slice[:len(slice)-1]
fmt.Printf("删除最后一个元素: %v\n", slice)
// 重置切片
slice = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// 3. 删除中间元素(保持顺序)
index := 4
slice = append(slice[:index], slice[index+1:]...)
fmt.Printf("删除索引4的元素: %v\n", slice)
// 重置切片
slice = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// 4. 删除中间元素(不保持顺序,更高效)
index = 4
slice[index] = slice[len(slice)-1] // 用最后一个元素覆盖要删除的元素
slice = slice[:len(slice)-1] // 缩短切片
fmt.Printf("快速删除索引4的元素: %v\n", slice)
// 5. 删除多个元素
slice = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
start, end := 3, 7
slice = append(slice[:start], slice[end:]...)
fmt.Printf("删除索引3-6的元素: %v\n", slice)
}
// 删除切片元素的通用函数
func removeElement(slice []int, index int) []int {
if index < 0 || index >= len(slice) {
return slice
}
return append(slice[:index], slice[index+1:]...)
}
// 删除指定值的第一个出现
func removeValue(slice []int, value int) []int {
for i, v := range slice {
if v == value {
return append(slice[:i], slice[i+1:]...)
}
}
return slice
}#Slice Insertion Operations
func main() {
slice := []int{1, 2, 4, 5}
// 1. 在开头插入
slice = append([]int{0}, slice...)
fmt.Printf("在开头插入0: %v\n", slice)
// 2. 在末尾插入
slice = append(slice, 6)
fmt.Printf("在末尾插入6: %v\n", slice)
// 3. 在中间插入
index := 3
value := 3
slice = append(slice[:index+1], slice[index:]...)
slice[index] = value
fmt.Printf("在索引3插入3: %v\n", slice)
// 4. 批量插入
slice2 := []int{1, 2, 6, 7}
insertValues := []int{3, 4, 5}
insertIndex := 2
// 创建新切片用于插入
result := make([]int, 0, len(slice2)+len(insertValues))
result = append(result, slice2[:insertIndex]...)
result = append(result, insertValues...)
result = append(result, slice2[insertIndex:]...)
fmt.Printf("批量插入: %v\n", result)
}
// 通用插入函数
func insertElement(slice []int, index, value int) []int {
if index < 0 {
index = 0
}
if index > len(slice) {
index = len(slice)
}
slice = append(slice[:index+1], slice[index:]...)
slice[index] = value
return slice
}
// 批量插入函数
func insertElements(slice []int, index int, values []int) []int {
if index < 0 {
index = 0
}
if index > len(slice) {
index = len(slice)
}
result := make([]int, 0, len(slice)+len(values))
result = append(result, slice[:index]...)
result = append(result, values...)
result = append(result, slice[index:]...)
return result
}#🎯 Practical Examples
#Dynamic Array Implementation
// 动态数组结构
type DynamicArray struct {
data []int
size int
capacity int
}
func NewDynamicArray() *DynamicArray {
return &DynamicArray{
data: make([]int, 0, 2),
size: 0,
capacity: 2,
}
}
func (da *DynamicArray) Add(value int) {
if da.size >= da.capacity {
da.resize()
}
da.data = append(da.data, value)
da.size++
}
func (da *DynamicArray) Get(index int) (int, bool) {
if index < 0 || index >= da.size {
return 0, false
}
return da.data[index], true
}
func (da *DynamicArray) Set(index, value int) bool {
if index < 0 || index >= da.size {
return false
}
da.data[index] = value
return true
}
func (da *DynamicArray) Remove(index int) bool {
if index < 0 || index >= da.size {
return false
}
copy(da.data[index:], da.data[index+1:])
da.data = da.data[:da.size-1]
da.size--
return true
}
func (da *DynamicArray) resize() {
da.capacity *= 2
newData := make([]int, da.size, da.capacity)
copy(newData, da.data)
da.data = newData
}
func (da *DynamicArray) Size() int {
return da.size
}
func (da *DynamicArray) Capacity() int {
return da.capacity
}
func (da *DynamicArray) ToSlice() []int {
result := make([]int, da.size)
copy(result, da.data[:da.size])
return result
}
func main() {
// 测试动态数组
arr := NewDynamicArray()
fmt.Println("=== 动态数组测试 ===")
// 添加元素
for i := 0; i < 10; i++ {
arr.Add(i * 10)
fmt.Printf("添加 %d: 大小=%d, 容量=%d\n", i*10, arr.Size(), arr.Capacity())
}
fmt.Printf("数组内容: %v\n", arr.ToSlice())
// 获取元素
if value, ok := arr.Get(5); ok {
fmt.Printf("索引5的值: %d\n", value)
}
// 修改元素
arr.Set(5, 999)
fmt.Printf("修改后数组: %v\n", arr.ToSlice())
// 删除元素
arr.Remove(3)
fmt.Printf("删除索引3后: %v\n", arr.ToSlice())
}#Stack and Queue Implementation
// 栈实现
type Stack struct {
items []int
}
func NewStack() *Stack {
return &Stack{items: make([]int, 0)}
}
func (s *Stack) Push(item int) {
s.items = append(s.items, item)
}
func (s *Stack) Pop() (int, bool) {
if len(s.items) == 0 {
return 0, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}
func (s *Stack) Peek() (int, bool) {
if len(s.items) == 0 {
return 0, false
}
return s.items[len(s.items)-1], true
}
func (s *Stack) IsEmpty() bool {
return len(s.items) == 0
}
func (s *Stack) Size() int {
return len(s.items)
}
// 队列实现
type Queue struct {
items []int
}
func NewQueue() *Queue {
return &Queue{items: make([]int, 0)}
}
func (q *Queue) Enqueue(item int) {
q.items = append(q.items, item)
}
func (q *Queue) Dequeue() (int, bool) {
if len(q.items) == 0 {
return 0, false
}
item := q.items[0]
q.items = q.items[1:]
return item, true
}
func (q *Queue) Front() (int, bool) {
if len(q.items) == 0 {
return 0, false
}
return q.items[0], true
}
func (q *Queue) IsEmpty() bool {
return len(q.items) == 0
}
func (q *Queue) Size() int {
return len(q.items)
}
func main() {
// 测试栈
fmt.Println("=== 栈测试 ===")
stack := NewStack()
// 入栈
for i := 1; i <= 5; i++ {
stack.Push(i * 10)
fmt.Printf("入栈 %d, 栈大小: %d\n", i*10, stack.Size())
}
// 查看栈顶
if top, ok := stack.Peek(); ok {
fmt.Printf("栈顶元素: %d\n", top)
}
// 出栈
for !stack.IsEmpty() {
if item, ok := stack.Pop(); ok {
fmt.Printf("出栈 %d, 剩余大小: %d\n", item, stack.Size())
}
}
// 测试队列
fmt.Println("\n=== 队列测试 ===")
queue := NewQueue()
// 入队
for i := 1; i <= 5; i++ {
queue.Enqueue(i * 10)
fmt.Printf("入队 %d, 队列大小: %d\n", i*10, queue.Size())
}
// 查看队首
if front, ok := queue.Front(); ok {
fmt.Printf("队首元素: %d\n", front)
}
// 出队
for !queue.IsEmpty() {
if item, ok := queue.Dequeue(); ok {
fmt.Printf("出队 %d, 剩余大小: %d\n", item, queue.Size())
}
}
}#🎓 Summary
In this chapter, we deeply learned about Go slices:
- ✅ Slice basics: declaration, initialization, internal structure
- ✅ Slice operations: append, copy, slicing
- ✅ Advanced operations: growth mechanism, deletion, insertion
- ✅ Practical applications: dynamic array, stack, and queue implementations
Slices are the most commonly used data structure in Go. Mastering slice usage is essential for Go development.
Next, we will learn about Go Range and master Go's iteration mechanism.
::: tip Slice Usage Tips
- Prefer slices over arrays
- Pre-allocating capacity can improve performance
- Be aware of slices sharing the underlying array
- Watch for memory leaks when deleting elements :::