当前位置: 首页 > news >正文

Go基础:Go语言中集合详解(包括:数组、切片、Map、列表等)

文章目录

    • 一、集合概述
    • 二、数组(array)详解
      • 2.1 定义与特性
      • 2.2 数组的语法
      • 2.3 数组循环
    • 三、切片(slice)详解
      • 3.1 定义与特性
      • 3.2 切片的语法
      • 3.3 初始化方式
      • 3.4 数组与切片的区别
      • 3.5 切片的操作
    • 四、映射(map)详解
      • 4.1 Map 的定义与初始化
      • 4.2 Map 的基本操作
      • 4.3 Map 的并发安全
    • 五、列表(list)详解
      • 5.1 List定义和特点
      • 5.2 数组与列表的对比
      • 5.3 List的基本操作
      • 5.4 List使用的案例代码

一、集合概述

在实际需求中,我们会有很多同一类型的元素放在一起的场景,这就是集合,例如 100 个数字,10 个字符串等。在 Go 语言中,数组(array)、切片(slice)、映射(map)这些都是集合类型,用于存放同一类元素。虽然都是集合,但用处又不太一样。

二、数组(array)详解

2.1 定义与特性

数组存放的是固定长度、相同类型的数据,而且这些存放的元素是在内存中是连续的。所存放的数据类型没有限制,可以是整型、字符串甚至自定义。其长度在定义时确定,不可更改。数组的特性:

  • 固定长度:长度是数组类型的一部分,[3]int[5]int 是不同的类型。
  • 值类型:数组是值类型,赋值或作为参数传递时会复制整个数组。

2.2 数组的语法

1、基本语法

// var arrayName [length]elementType
array:=[5]string{"a","b","c","d","e"}

示例代码:

package main
import "fmt"
func main() {// 定义一个长度为3的整型数组var arr [3]intarr[0] = 10arr[1] = 20arr[2] = 30fmt.Println("数组:", arr) // 输出: [10 20 30]
}

2、初始化方式
静态初始化:arr := [3]int{10, 20, 30}
动态初始化:arr := [...]int{10, 20, 30} // 编译器自动推断长度

3、示例代码

package main
import "fmt"
func modifyArray(arr [3]int) {arr[0] = 100
}
func main() {arr := [3]int{10, 20, 30}modifyArray(arr)fmt.Println("数组:", arr) // 输出: [10 20 30],原数组未被修改
}

2.3 数组循环

使用传统的 for 循环遍历数组,输出对应的索引和对应的值,这种方式很烦琐,一般不使用,大部分情况下,我们使用的是 for range 这种 Go 语言的新型循环,如下面的代码所示:

for i,v:=range array{fmt.Printf("数组索引:%d,对应值:%s\n", i, v)
}

这种方式和传统 for 循环的结果是一样的。对于数组,range 表达式返回两个结果:

  • 第一个是数组的索引;
  • 第二个是数组的值。

在上面的示例中,把返回的两个结果分别赋值给 i 和 v 这两个变量,就可以使用它们了。相比传统的 for 循环,for range 要更简洁,如果返回的值用不到,可以使用 _ 下划线丢弃,如下面的代码所示:

for _,v:=range array{fmt.Printf("对应值:%s\n", v)
}

数组的索引通过 _ 就被丢弃了,只使用数组的值 v 即可。

三、切片(slice)详解

3.1 定义与特性

切片是对数组的一个连续片段的引用,其长度可以动态变化。切片和数组类似,可以把它理解为动态数组。切片是基于数组实现的,它的底层就是一个数组。对数组任意分隔,就可以得到一个切片。切片的特性:

  • 动态长度:切片的长度可以动态调整。
  • 引用类型:切片是对底层数组的引用,修改切片会影响底层数组。
  • 容量:切片的容量是从切片的第一个元素到底层数组末尾的元素数量。

3.2 切片的语法

var sliceName []elementType

示例代码

package main
import "fmt"
func main() {// 定义一个整型切片var slice []intslice = append(slice, 10, 20, 30)fmt.Println("切片:", slice) // 输出: [10 20 30]
}

3.3 初始化方式

从数组创建切片

arr := [5]int{10, 20, 30, 40, 50}
slice := arr[1:4] // 包含索引1到3的元素
fmt.Println("切片:", slice) // 输出: [20 30 40]

使用 make 创建切片

slice := make([]int, 3, 5) // 长度为3,容量为5
fmt.Println("切片:", slice) // 输出: [0 0 0]

示例代码

package main
import "fmt"
func modifySlice(slice []int) {slice[0] = 100
}
func main() {slice := []int{10, 20, 30}modifySlice(slice)fmt.Println("切片:", slice) // 输出: [100 20 30],原切片被修改
}

3.4 数组与切片的区别

特性数组切片
长度固定动态
类型长度是类型的一部分长度不是类型的一部分
传递方式值传递引用传递
使用场景长度固定的数据集合动态变化的数据集合

3.5 切片的操作

1. 添加元素
使用 append 函数向切片添加元素:

slice := []int{10, 20, 30}
slice = append(slice, 40)
fmt.Println("切片:", slice) // 输出: [10 20 30 40]

2. 删除元素
通过切片操作删除元素:

slice := []int{10, 20, 30, 40}
slice = append(slice[:1], slice[2:]...) // 删除索引1的元素
fmt.Println("切片:", slice) // 输出: [10 30 40]

3. 遍历切片
使用 forfor-range 遍历切片:

slice := []int{10, 20, 30}
for i, v := range slice {fmt.Printf("索引: %d, 值: %d\n", i, v)
}

四、映射(map)详解

在 Go 语言中,map 是一个无序的 K-V 键值对集合,结构为 map[K]V。其中 K 对应 Key,V 对应 Value。map 中所有的 Key 必须具有相同的类型,Value 也同样,但 Key 和 Value 的类型可以不同。此外,Key 的类型必须支持 == 比较运算符,这样才可以判断它是否存在,并保证 Key 的唯一。

Go 语言中的 map 是一种非常重要的数据结构,类似于其他语言中的字典或哈希表。map 提供了高效的查找、插入和删除操作,平均时间复杂度为 O(1)。

4.1 Map 的定义与初始化

定义:map 的语法为 map[KeyType]ValueType,其中 KeyType 必须是可比较的类型(如 intstring、指针等),ValueType 可以是任意类型。示例代码如下:

package main
import "fmt"
func main() {// 定义一个 map,key 是 string,value 是 intvar m map[string]intfmt.Println(m) // 输出: map[]
}

初始化:map 必须使用 make 函数或字面量初始化,否则为 nil,无法直接赋值。示例代码如下

// 使用 make 初始化 
// nameAgeMap:=make(map[string]int)
m1 := make(map[string]int)
m1["age"] = 25
fmt.Println(m1) // 输出: map[age:25]
// 使用字面量初始化
m2 := map[string]int{"age": 30, "height": 180}
fmt.Println(m2) // 输出: map[age:30 height:180]

4.2 Map 的基本操作

1、添加和修改
直接通过 key 赋值即可,如果 key 不存在则添加,存在则修改。示例代码

m := make(map[string]int)
m["age"] = 25    // 添加
m["age"] = 26    // 修改
fmt.Println(m)   // 输出: map[age:26]

2、删除
使用 delete 函数删除指定 key 的键值对。示例代码

m := map[string]int{"age": 25, "height": 180}
delete(m, "height")
fmt.Println(m) // 输出: map[age:25]

3、查找
通过 value, ok := m[key] 判断 key 是否存在。示例代码

m := map[string]int{"age": 25}
if value, ok := m["age"]; ok {fmt.Println("age 存在,值为:", value) // 输出: age 存在,值为: 25
} else {fmt.Println("age 不存在")
}

4、Map 的遍历
使用 for-range 遍历 map,注意遍历顺序是随机的(Go 1.0+ 保证每次遍历顺序不同)。示例代码

m := map[string]int{"age": 25, "height": 180, "weight": 70}
for key, value := range m {fmt.Printf("key: %s, value: %d\n", key, value)
}

输出

key: age, value: 25
key: height, value: 180
key: weight, value: 70

需要注意的是 map 的遍历是无序的,也就是说你每次遍历,键值对的顺序可能会不一样。如果想按顺序遍历,可以先获取所有的 Key,并对 Key 排序,然后根据排序好的 Key 获取对应的 Value。

5、Map 的大小
和数组切片不一样,map 是没有容量的,它只有长度,也就是 map 的大小(键值对的个数)。要获取 map 的大小,使用内置的 len 函数即可,如下代码所示:

fmt.Println(len(nameAgeMap))

4.3 Map 的并发安全

Go 的原生 map 不是并发安全的,多个 goroutine 同时读写会导致 panic。解决方案包括:

  1. 使用 sync.Mutex 加锁。
  2. 使用 sync.Map(Go 1.9+ 提供)。

1、使用 sync.Mutex ,示例代码:

package main
import ("fmt""sync"
)
func main() {var m map[string]intm = make(map[string]int)var mu sync.Mutexvar wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(i int) {defer wg.Done()mu.Lock()m["key"] = imu.Unlock()}(i)}wg.Wait()fmt.Println(m) // 输出: map[key:9](值可能不同)
}

2、使用 sync.Map,示例代码:

package main
import ("fmt""sync"
)
func main() {var m sync.Mapvar wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(i int) {defer wg.Done()m.Store("key", i)}(i)}wg.Wait()if value, ok := m.Load("key"); ok {fmt.Println("key 的值为:", value) // 输出: key 的值为: 9(值可能不同)}
}

五、列表(list)详解

5.1 List定义和特点

Go语言中的列表(List)是一种常用的数据结构,通常通过标准库中的 container/list 包实现。它是一种双向链表,支持高效的插入、删除和遍历操作。以下从定义、特点、基本操作和实例应用四个方面进行详细解析,并附上案例代码。

Go语言并没有内置的列表类型,但通过 container/list 包提供了双向链表的实现。其主要特点包括:

  • 双向链表结构:每个节点包含指向前驱和后继节点的指针,支持双向遍历。
  • 动态大小:列表的长度可以动态调整,无需预先分配固定空间。
  • 支持任意类型:通过 interface{} 类型存储元素,可以容纳不同类型的数据。

5.2 数组与列表的对比

特性数组(Array)列表(List)
长度固定,定义时确定动态,可以随时调整
内存结构连续存储,支持高效随机访问非连续存储,通过指针链接节点
访问方式支持通过索引直接访问(如arr[i]不支持索引访问,需遍历节点
插入/删除效率低,需移动元素效率高,只需调整指针
适用场景需要固定大小、高效随机访问的场景需要频繁插入、删除操作的场景

5.3 List的基本操作

container/list 包提供了丰富的方法来操作列表,以下是常用操作及其说明:

1. 初始化列表

  • 使用 list.New() 创建一个空列表。
  • 示例代码:l := list.New()

2. 插入元素

  • PushFront(v interface{}):在列表头部插入元素。
  • PushBack(v interface{}):在列表尾部插入元素。
  • InsertBefore(v interface{}, mark *Element):在指定节点前插入元素。
  • InsertAfter(v interface{}, mark *Element):在指定节点后插入元素。
  • 示例代码:
    l.PushBack("尾部元素")
    l.PushFront("头部元素")
    

3. 删除元素

  • Remove(e *Element):删除指定节点,并返回节点的值。
  • 示例代码:
    element := l.Front() // 获取头部节点
    l.Remove(element)    // 删除头部节点
    

4. 遍历列表

  • 使用 Front()Next() 方法从头到尾遍历列表。
  • 示例代码:
    for e := l.Front(); e != nil; e = e.Next() {fmt.Println(e.Value)
    }
    

5. 获取列表长度

  • Len() 方法返回列表的长度。
  • 示例代码:
    length := l.Len()
    fmt.Println("列表长度:", length)
    

5.4 List使用的案例代码

以下是一个完整的案例代码,展示如何初始化列表、插入元素、遍历列表以及删除元素:

package main
import ("container/list""fmt"
)
func main() {// 初始化列表l := list.New()// 插入元素l.PushBack("尾部元素1")l.PushBack("尾部元素2")l.PushFront("头部元素1")// 遍历列表fmt.Println("列表遍历结果:")for e := l.Front(); e != nil; e = e.Next() {fmt.Println(e.Value)}// 删除元素element := l.Front() // 获取头部节点l.Remove(element)    // 删除头部节点// 再次遍历列表fmt.Println("\n删除头部节点后的列表:")for e := l.Front(); e != nil; e = e.Next() {fmt.Println(e.Value)}// 获取列表长度fmt.Println("\n当前列表长度:", l.Len())
}

运行结果:

列表遍历结果:
头部元素1
尾部元素1
尾部元素2
删除头部节点后的列表:
尾部元素1
尾部元素2
当前列表长度: 2
http://www.dtcms.com/a/392208.html

相关文章:

  • 《算法闯关指南:优选算法--滑动窗口》--09长度最小的子数串,10无重复字符的最长字串
  • 请卸载xshell,一款国产的终端工具,界面漂亮,功能强大,支持win,mac,linux平台,安全免费
  • 用批处理文件实现Excel和word文件的重造
  • unseping(反序列化漏洞)
  • 麒麟系统 word转为pdf
  • 【Codex CLI 配置指南(小白速通版)】
  • R及RStudio的配置与安装
  • 深度解析:基于 ODBC连接 KingbaseES 数据库的完整操作与实践
  • springboot川剧科普平台(代码+数据库+LW)
  • Vue中的监听方式
  • CentOS 7系统解决yum报错
  • GD32VW553-IOT V2开发版【温湿度检测】
  • Perplexica - 开源AI搜索引擎,让搜索更智能
  • Windows在VSCode Cline中安装Promptx
  • 深入解析 Spring AI 系列:解析返回参数处理
  • LeetCode:34.合并K个升序链表
  • 精细化关键词优化:提升SEO效果的长尾策略解析
  • Go基础:Go语言详细介绍,环境搭建,及第一个程序详解
  • 【开题答辩全过程】以 HL新闻为例,包含答辩的问题和答案
  • docker运行wonderShaper实现网卡限速
  • Windows 安装 Docker Desktop 到 D 盘完整教程(含迁移方案)
  • 基于陌讯AI检测算法本地化部署教程:基于Docker的环境配置与性能测试
  • Docker Docker Compose 完整入门与实用技巧
  • ARP协议工作原理分析(基于Wireshark)
  • CKS-CN 考试知识点分享(14) Istio网络策略
  • TCP 协议全解析:握手、挥手、重传与流控的深度剖析
  • 计算机视觉(opencv)实战二十七——目标跟踪
  • 深度学习中神经网络与损失函数优化
  • 整体设计 完整的逻辑链条 之1 点dots/线lines/面faces 的三曲:三进三出的三个来回
  • 微调基本理论