Go之路 - 4.go的集合[完整版]

1. 数组(Array)

数组是固定长度的相同类型元素的集合。

基本用法

go 复制代码
package main

import "fmt"

func main() {
    // 声明数组
    var arr1 [3]int               // 声明长度为3的int数组
    arr2 := [3]int{1, 2, 3}       // 声明并初始化
    arr3 := [...]int{1, 2, 3, 4}  // 编译器推导长度
    
    fmt.Println("arr1:", arr1)    // [0 0 0]
    fmt.Println("arr2:", arr2)    // [1 2 3]
    fmt.Println("arr3:", arr3)    // [1 2 3 4]
    
    // 访问和修改元素
    arr2[0] = 100
    fmt.Println("arr2[0]:", arr2[0])  // 100
    
    // 遍历数组
    for i := 0; i < len(arr2); i++ {
        fmt.Printf("arr2[%d] = %d\n", i, arr2[i])
    }
    
    // 使用range遍历
    for index, value := range arr3 {
        fmt.Printf("Index: %d, Value: %d\n", index, value)
    }
}

多维数组

go 复制代码
func multiDimensionalArray() {
    // 二维数组
    var matrix [3][3]int
    
    // 初始化
    matrix = [3][3]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }
    
    // 访问元素
    fmt.Println("matrix[1][2]:", matrix[1][2])  // 6
    
    // 遍历二维数组
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf("%d ", matrix[i][j])
        }
        fmt.Println()
    }
}

2. 切片(Slice)

切片是动态长度的数组,是Go中最常用的集合类型。

基本用法

go 复制代码
func sliceBasics() {
    // 创建切片的多种方式
    var s1 []int                  // nil切片
    s2 := []int{1, 2, 3}         // 字面量创建
    s3 := make([]int, 3)         // 长度为3,容量为3
    s4 := make([]int, 3, 5)      // 长度为3,容量为5
    
    // 从数组创建切片
    arr := [5]int{1, 2, 3, 4, 5}
    s5 := arr[1:4]               // [2, 3, 4]
    s6 := arr[:3]                // [1, 2, 3]
    s7 := arr[2:]                // [3, 4, 5]
    
    // 切片操作
    fmt.Println("长度:", len(s4))  // 3
    fmt.Println("容量:", cap(s4))  // 5
    
    // 添加元素
    s2 = append(s2, 4, 5)       // [1, 2, 3, 4, 5]
    s2 = append(s2, []int{6, 7}...) // 追加切片
    
    // 复制切片
    s8 := make([]int, len(s2))
    copy(s8, s2)
    
    // 删除元素
    s9 := []int{1, 2, 3, 4, 5}
    // 删除索引2的元素
    s9 = append(s9[:2], s9[3:]...)
    fmt.Println("删除后:", s9)  // [1, 2, 4, 5]
}

切片高级操作

go 复制代码
func advancedSliceOperations() {
    // 切片作为栈
    stack := []int{}
    
    // 入栈
    stack = append(stack, 1)  // push 1
    stack = append(stack, 2)  // push 2
    
    // 出栈
    if len(stack) > 0 {
        top := stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        fmt.Println("出栈:", top)
    }
    
    // 切片作为队列(低效,推荐使用container/list)
    queue := []int{1, 2, 3}
    // 出队
    if len(queue) > 0 {
        front := queue[0]
        queue = queue[1:]
        fmt.Println("出队:", front)
    }
    
    // 切片分割
    data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    chunkSize := 3
    var chunks [][]int
    
    for i := 0; i < len(data); i += chunkSize {
        end := i + chunkSize
        if end > len(data) {
            end = len(data)
        }
        chunks = append(chunks, data[i:end])
    }
    fmt.Println("分块:", chunks)
}

3. 映射(Map)

Map是键值对的集合,也称为字典。

基本用法

go 复制代码
func mapBasics() {
    // 创建map
    var m1 map[string]int        // nil map
    m2 := make(map[string]int)   // 空map
    m3 := map[string]int{        // 字面量创建
        "apple":  5,
        "banana": 10,
        "orange": 8,
    }
    
    // 添加/修改元素
    m2["apple"] = 3
    m2["banana"] = 6
    m2["apple"] = 4              // 修改值
    
    // 访问元素
    value := m3["apple"]
    fmt.Println("apple:", value)
    
    // 检查key是否存在
    if v, ok := m3["grape"]; ok {
        fmt.Println("grape exists:", v)
    } else {
        fmt.Println("grape not found")
    }
    
    // 删除元素
    delete(m3, "orange")
    
    // 遍历map
    for key, value := range m3 {
        fmt.Printf("%s: %d\n", key, value)
    }
    
    // 只遍历key
    for key := range m3 {
        fmt.Println("Key:", key)
    }
    
    // 只遍历value
    for _, value := range m3 {
        fmt.Println("Value:", value)
    }
}

Map高级操作

go 复制代码
func advancedMapOperations() {
    // 嵌套map
    students := map[string]map[string]float64{
        "张三": {
            "数学": 85.5,
            "英语": 90.0,
        },
        "李四": {
            "数学": 92.0,
            "物理": 88.5,
        },
    }
    
    // 访问嵌套map
    if scores, ok := students["张三"]; ok {
        fmt.Println("张三的数学成绩:", scores["数学"])
    }
    
    // 反转map(值->键)
    original := map[string]int{"a": 1, "b": 2, "c": 1}
    reversed := make(map[int][]string)
    
    for key, value := range original {
        reversed[value] = append(reversed[value], key)
    }
    fmt.Println("反转后的map:", reversed)
    
    // map合并
    map1 := map[string]int{"a": 1, "b": 2}
    map2 := map[string]int{"b": 3, "c": 4}
    
    for key, value := range map2 {
        map1[key] = value  // map2会覆盖map1的相同key
    }
    fmt.Println("合并后:", map1)
}

4. 列表(List)

使用标准库的container/list实现双向链表。

go 复制代码
package main

import (
    "container/list"
    "fmt"
)

func listBasics() {
    // 创建列表
    l := list.New()
    
    // 添加元素
    l.PushBack(1)      // 在尾部添加
    l.PushBack(2)
    l.PushFront(0)     // 在头部添加
    
    // 插入元素
    for e := l.Front(); e != nil; e = e.Next() {
        if e.Value == 1 {
            l.InsertBefore(0.5, e)  // 在1前面插入0.5
            break
        }
    }
    
    // 遍历列表
    fmt.Print("正向遍历: ")
    for e := l.Front(); e != nil; e = e.Next() {
        fmt.Printf("%v ", e.Value)
    }
    
    fmt.Print("\n反向遍历: ")
    for e := l.Back(); e != nil; e = e.Prev() {
        fmt.Printf("%v ", e.Value)
    }
    
    // 删除元素
    for e := l.Front(); e != nil; e = e.Next() {
        if e.Value == 1 {
            l.Remove(e)
            break
        }
    }
    
    fmt.Print("\n删除后: ")
    for e := l.Front(); e != nil; e = e.Next() {
        fmt.Printf("%v ", e.Value)
    }
}

5. 集合操作示例

go 复制代码
func collectionExamples() {
    // 示例1:数组和切片转换
    arr := [5]int{1, 2, 3, 4, 5}
    slice := arr[:]  // 数组转切片
    
    // 切片转数组(Go 1.17+)
    slice2 := []int{1, 2, 3, 4, 5}
    var arr2 [5]int
    copy(arr2[:], slice2)  // 方法1
    // 或
    arr3 := [5]int(slice2) // 方法2(需要长度匹配)
    
    // 示例2:切片去重
    numbers := []int{1, 2, 2, 3, 4, 4, 4, 5}
    unique := make([]int, 0)
    seen := make(map[int]bool)
    
    for _, num := range numbers {
        if !seen[num] {
            seen[num] = true
            unique = append(unique, num)
        }
    }
    fmt.Println("去重后:", unique)
    
    // 示例3:统计词频
    words := []string{"apple", "banana", "apple", "orange", "banana", "apple"}
    wordCount := make(map[string]int)
    
    for _, word := range words {
        wordCount[word]++
    }
    fmt.Println("词频统计:", wordCount)
    
    // 示例4:矩阵转置
    matrix := [][]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }
    
    rows := len(matrix)
    cols := len(matrix[0])
    transposed := make([][]int, cols)
    
    for i := range transposed {
        transposed[i] = make([]int, rows)
        for j := range transposed[i] {
            transposed[i][j] = matrix[j][i]
        }
    }
    fmt.Println("转置矩阵:", transposed)
}

6. 内置函数

go 复制代码
func builtinFunctions() {
    // len() - 获取长度
    arr := [3]int{1, 2, 3}
    slice := []int{1, 2, 3, 4}
    m := map[string]int{"a": 1, "b": 2}
    
    fmt.Println("数组长度:", len(arr))   // 3
    fmt.Println("切片长度:", len(slice))  // 4
    fmt.Println("map长度:", len(m))      // 2
    
    // cap() - 获取容量(仅数组、切片、通道)
    fmt.Println("切片容量:", cap(slice))  // 4
    
    // make() - 创建切片、映射、通道
    s := make([]int, 3, 5)
    mm := make(map[string]int)
    
    // append() - 向切片追加元素
    s = append(s, 6, 7)
    
    // copy() - 复制切片
    s2 := make([]int, len(s))
    copy(s2, s)
    
    // delete() - 删除map元素
    delete(mm, "key")
    
    // close() - 关闭通道(通道也是一种集合)
}

总结

Go语言的集合类型非常丰富,每种都有其特定的用途:

  1. 数组:性能最好,但长度固定
  2. 切片:最常用,灵活的动态数组
  3. 映射:键值对存储,快速查找
  4. 列表:双向链表,灵活插入删除

选择哪种集合取决于具体的需求:

  • 大多数情况下使用切片
  • 需要键值对查找时用映射
  • 需要固定长度和高性能时用数组
  • 需要频繁在中间插入删除时用列表

在实际开发中,切片和映射是最常用的两种集合类型。

相关推荐
卡尔AI工坊2 小时前
万众瞩目的 GPT 5.2,连个火柴人游戏都做不明白?
后端·算法
coding随想2 小时前
JavaScript Notifications API:告别alert弹窗,开启沉浸式用户体验革命!
开发语言·javascript·ux
阿海5742 小时前
卸载php的shell脚本
开发语言·php
码界奇点2 小时前
基于Python与GitHub Actions的正方教务成绩自动推送系统设计与实现
开发语言·python·车载系统·自动化·毕业设计·github·源代码管理
哈哈哈笑什么2 小时前
Spring Boot接口国际化异常信息方案
java·spring boot·后端
qq_162987692 小时前
SpringBoot框架选型
java·spring boot·后端
kaikaile19952 小时前
MATLAB计算卫星星下点轨迹
开发语言·算法·matlab
武藤一雄2 小时前
C# 万字拆解线程间通讯?
后端·微软·c#·.net·.netcore·多线程
阿里巴啦3 小时前
从零搭建移动端数字人生成应用:React + Go + D‑ID 实战
react.js·golang·状态模式·数字人·did·ai移动端数字人