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

【Golang】--- Map

Map

    • 前言
    • 一、Map 概述
    • 二、Map 的定义与初始化
      • 2.1 声明 Map
      • 2.2 使用 make 函数初始化 Map
      • 2.3 直接初始化并赋值
    • 三、Map 的基本操作
      • 3.1 添加元素
      • 3.2 获取元素
      • 3.3 修改元素
      • 3.4 删除元素
      • 3.5 获取 Map 的长度
    • 四、Map 的遍历
      • 4.1 遍历键和值
      • 4.2 只遍历键
      • 4.3 只遍历值
    • 五、Map 的特性
      • 5.1 无序性
      • 5.2 引用类型
      • 5.3 键的类型限制
      • 5.4 扩容机制
    • 六、Map 与切片结合使用
      • 6.1 示例:存储用户信息
    • 七、Map 的注意事项
      • 7.1 不要使用 nil Map
      • 7.2 键的唯一性
      • 7.3 并发安全问题
      • 7.4 性能优化
    • 总结

前言

在 Go 语言中,Map 是一种非常重要的数据结构,它以键值对(key-value)的形式存储数据,能够通过键快速快速检索对应的值,在实际开发中有着广泛的应用。本文将围绕 Go 语言中 Map 的定义、使用、特性、高级操作及实战技巧等方面进行全面深入的讲解,帮助读者彻底掌握 Map 的相关知识。

一、Map 概述

Map 是一种无序的键值对集合,它的核心特点是通过键来快速定位和访问值,这使得 Map 在需要快速查找、插入和删除数据的场景中表现出色。

与数组和切片不同,Map 没有固定的长度,并且是无序的,我们无法像访问数组元素那样通过索引来访问 Map 中的元素,只能通过键来操作。同时,Map 也是一种引用类型,这意味着当我们将一个 Map 赋值给另一个变量时,它们指向的是同一块内存地址,修改其中一个变量会影响到另一个变量。

二、Map 的定义与初始化

在 Go 语言中,定义和初始化 Map 有多种方式,我们需要根据实际需求选择合适的方式。

2.1 声明 Map

声明 Map 的基本语法如下:

var mapName map[keyType]valueType

其中,mapName 是 Map 的名称,keyType 是键的数据类型,valueType 是值的数据类型。

例如,声明一个键为 int 类型、值为 string 类型的 Map:

var map1 map[int]string

需要注意的是,仅仅声明 Map 变量并不会分配内存空间,此时的 Map 处于 nil 状态,不能直接使用,否则会引发运行时错误。我们可以通过判断 Map 是否为 nil 来验证这一点:

var map1 map[int]string
if map1 == nil {fmt.Println("map1==nil")
}

在这里插入图片描述

2.2 使用 make 函数初始化 Map

使用 make 函数可以为 Map 分配内存空间,完成初始化操作。其语法如下:

mapName := make(map[keyType]valueType)

也可以指定 Map 的初始容量:

mapName := make(map[keyType]valueType, initialCapacity)

指定初始容量可以在一定程度上提高 Map 的性能,避免在后续添加元素时频繁进行扩容操作。

例如:

var map2 = make(map[string]string) // 创建一个键和值都是 string 类型的 Map
map3 := make(map[int]int, 10) // 创建一个键和值都是 int 类型,初始容量为 10 的 Map

2.3 直接初始化并赋值

我们还可以在定义 Map 的同时进行初始化并赋值,语法如下:

mapName := map[keyType]valueType{key1: value1, key2: value2, ..., keyn: valuen}

例如:

var map4 = map[string]int{"Go": 100, "Java": 10, "C": 60}
map5 := map[float64]string{3.14: "圆周率", 1.618: "黄金分割比"}

通过这种方式创建的 Map 已经完成了初始化,可以直接使用。

三、Map 的基本操作

Map 的基本操作包括添加元素、获取元素、修改元素、删除元素以及获取 Map 的长度等,这些操作是我们使用 Map 时最常用的功能。

3.1 添加元素

向 Map 中添加元素的语法非常简单,使用 mapName[key] = value 即可:

map1 := make(map[int]string)
map1[100] = "xjy"
map1[200] = "why"

需要注意的是,如果添加元素时使用的键已经存在于 Map 中,那么新的值会覆盖原来的值。例如:

map1[100] = "xjy1111" // 此时键 100 对应的值变为 "xjy1111"

3.2 获取元素

获取 Map 中元素的值可以通过 mapName[key] 来实现:

map1 := map[int]string{100: "xjy1111", 200: "why"}
fmt.Println(map1[200]) // 输出:why

如果获取元素时使用的键不存在于 Map 中,会返回该值类型的零值。例如,对于值类型为 string 的 Map,当键不存在时会返回空字符串:

fmt.Println(map1[1]) // 输出:(空字符串)

为了判断一个键是否存在于 Map 中,Go 语言提供了一种特殊的语法:value, ok := mapName[key]
其中,value 是获取到的值,如果键存在,oktrue,否则为 false。例如:

value, ok := map1[1]
if ok {fmt.Println("map key 存在的,value:", value)
} else {fmt.Println("map key 不存在的")
}

在这里插入图片描述

3.3 修改元素

修改 Map 中元素的值与添加元素的语法相同,只需使用存在的键为其赋予新值即可:

map1 := map[int]string{100: "xjy1111", 200: "why"}
map1[100] = "飞哥" // 将键 100 对应的值修改为 "飞哥"
fmt.Println(map1[100]) // 输出:飞哥

但是若元素不存在,就创建对应的key-value

map[1] = "xxxxxxxxxxxxxxx"

在这里插入图片描述

3.4 删除元素

使用 delete 函数可以删除 Map 中的元素,其语法为:

delete(mapName, key)

例如:

map1 := map[int]string{1: "xxxxxxxxxxxxxxx", 100: "飞哥", 200: "why"}
delete(map1, 1) // 删除键为 1 的元素
fmt.Println(map1) 

如果删除的键不存在于 Map 中,delete 函数不会做任何操作,也不会返回错误。

3.5 获取 Map 的长度

使用 len 函数可以获取 Map 中键值对的数量,即 Map 的长度:

map1 := map[int]string{100: "飞哥", 200: "why"}
fmt.Println(len(map1)) // 输出:2

需要注意的是,cap 函数不能用于 Map,这一点与切片不同。
在这里插入图片描述

四、Map 的遍历

遍历 Map 可以获取其中所有的键值对,在 Go 语言中,只能通过 for range 循环来遍历 Map。

4.1 遍历键和值

使用 for k, v := range mapName 可以同时遍历 Map 中的键和值,其中 k 是键,v 是对应的值。例如:

map1 := map[string]int{"Go": 100, "Java": 99, "C": 80, "Python": 60}
for k, v := range map1 {fmt.Printf("键:%s,值:%d\n", k, v)
}

运行上述代码,可能的输出结果如下(由于 Map 是无序的,每次运行的输出顺序可能不同):

键:Go,值:100
键:Java,值:99
键:C,值:80
键:Python,值:60

4.2 只遍历键

如果只需要遍历 Map 中的键,可以使用 for k := range mapName

map1 := map[string]int{"Go": 100, "Java": 99, "C": 80, "Python": 60}
for k := range map1 {fmt.Println("键:", k)
}

在这里插入图片描述

4.3 只遍历值

如果只需要遍历 Map 中的值,可以使用 for _, v := range mapName,其中下划线 _ 是匿名变量,用于忽略键:

map1 := map[string]int{"Go": 100, "Java": 99, "C": 80, "Python": 60}
for _, v := range map1 {fmt.Println("值:", v)
}

在这里插入图片描述

五、Map 的特性

5.1 无序性

Map 是无序的,这意味着我们无法保证遍历 Map 时得到的键值对顺序与添加时的顺序一致,也无法通过索引来访问 Map 中的元素。这是由 Map 内部的实现机制决定的,Map 使用哈希表来存储键值对,哈希表的存储顺序是不确定的。

5.2 引用类型

Map 是引用类型,当我们将一个 Map 赋值给另一个变量时,它们指向的是同一块内存地址。因此,修改其中一个变量会影响到另一个变量。例如:

map1 := map[string]int{"a": 1, "b": 2}
map2 := map1
map2["a"] = 100
fmt.Println(map1["a"]) // 输出:100
fmt.Println(map2["a"]) // 输出:100

在函数传参时,Map 也是以引用的方式传递的。这意味着在函数内部修改 Map 的内容,会影响到函数外部的 Map。例如:

func modifyMap(m map[string]int) {m["a"] = 200
}func main() {map1 := map[string]int{"a": 1, "b": 2}modifyMap(map1)fmt.Println(map1["a"]) // 输出:200
}

5.3 键的类型限制

Map 中的键可以是任意可比较的类型,如布尔类型、整数类型、浮点数类型、字符串类型、指针类型、数组类型等。但切片、Map、函数等不可比较的类型不能作为 Map 的键,否则会引发编译错误。

例如,以下代码是错误的:

// 错误示例:切片不能作为 Map 的键
map1 := map[[]int]string{[]int{1, 2}: "test"}

5.4 扩容机制

当 Map 中的元素数量超过其容量时,Map 会自动进行扩容。扩容会创建一个新的更大的哈希表,并将原来的元素复制到新的哈希表中。这个过程是自动完成的,我们不需要手动干预,但了解扩容机制有助于我们在使用 Map 时进行性能优化,例如在初始化 Map 时指定合适的初始容量,减少扩容的次数。

六、Map 与切片结合使用

在实际开发中,我们经常会将 Map 和切片结合起来使用,以实现更复杂的数据结构和功能。例如,我们可以使用切片来存储多个 Map,每个 Map 表示一个对象的信息。

6.1 示例:存储用户信息

下面是一个使用 Map 和切片存储用户信息的示例:

package mainimport "fmt"func main() {// 创建第一个用户的信息 Mapuser1 := make(map[string]string)user1["name"] = "wangwu"user1["age"] = "22"user1["sex"] = "男"user1["addr"] = "辽宁"// 创建第二个用户的信息 Mapuser2 := make(map[string]string)user2["name"] = "xieyke"user2["age"] = "24"user2["sex"] = "男"user2["addr"] = "四川"// 创建第三个用户的信息 Map 并直接初始化user3 := map[string]string{"name": "小红", "age": "29", "sex": "男", "addr": "地球"}// 创建一个切片,用于存储用户信息 MapuserDatas := make([]map[string]string, 0, 3)userDatas = append(userDatas, user1)userDatas = append(userDatas, user2)userDatas = append(userDatas, user3)// 遍历切片,输出用户的地址信息for _, user := range userDatas {fmt.Println(user["addr"])}
}

运行上述代码,输出结果如下:

辽宁
四川
地球

通过这种方式,我们可以方便地管理和操作多个对象的信息,提高代码的灵活性和可读性。
切片和map一般有两种组合,分别是:

  • map[可比较类型] []T:map的值是切片(一个键对应多个值)
  • []map[K]V:切片的元素是map(多个键值对集合的列表)

七、Map 的注意事项

7.1 不要使用 nil Map

未初始化的 Map 是 nil,不能对其进行添加、修改等操作,否则会引发运行时错误。在使用 Map 之前,一定要确保已经对其进行了初始化。

7.2 键的唯一性

Map 中的键是唯一的,当添加元素时,如果使用的键已经存在,新的值会覆盖原来的值。因此,在使用 Map 时,需要确保键的唯一性。

7.3 并发安全问题

Map 不是并发安全的,在多个 goroutine 同时对 Map 进行读写操作时,会引发数据竞争问题。如果需要在并发环境中使用 Map,可以使用 sync.Map,它是 Go 语言标准库中提供的并发安全的 Map。

7.4 性能优化

  • 初始化 Map 时指定合适的初始容量,可以减少 Map 扩容的次数,提高性能。
  • 尽量使用简单的类型作为键,因为复杂类型的哈希计算和比较操作会更耗时。
  • 避免频繁地对 Map 进行删除和添加操作,这可能会导致哈希表的重组,影响性能。

总结

Map 是 Go 语言中一种非常重要的数据结构,它以键值对的形式存储数据,具有快速查找、插入和删除的特点。本文详细介绍了 Map 的定义、初始化、基本操作、遍历方式、特性、与切片的结合使用等内容。在实际开发中,我们需要根据具体的需求合理地使用 Map,充分发挥其优势,提高代码的效率和质量。

http://www.dtcms.com/a/474371.html

相关文章:

  • 网站制作多少费用2345网址导航桌面版
  • i18n语言表查询性能优化实战:从8秒到0.1秒的蜕变
  • 从Java的Map到Redis数据结构迁移的性能优化实践
  • 深入解析Java并发编程中的Synchronized关键字工作原理与性能优化
  • 时间序列时域分析
  • 有没有什么网站可以直接在网上做试题并且可以给你判出来wordpress 标题编辑器
  • 高端网站建设必须要满足哪些要求三维家在线设计官网
  • 01_kubeadm安装k8s集群
  • C++Lambda 表达式与函数对象
  • 个人网站主页怎么做阿里云 域名 做网站
  • 数据结构:初识数据结构
  • 【Redis】用Redis实现分布式锁、乐观锁
  • 做好评做销量的网站桂林尚品网络科技有限公司
  • 网上接单做衣服哪个网站设计感十足的网站
  • Nginx黑白名单基于 IP 的黑白名单配置指南
  • 英文网站群建设如何做英文网站外链
  • 【金仓数据库产品体验官】Mycat适配KES分库分表体验
  • Unified AI Container
  • 接口测试(一)
  • 建设企业网站企业网上银行打死都不想干电商运营了
  • 汇编语言程序设计
  • python中进程和线程
  • 非对称加密使用举例
  • 多视图几何--密集匹配--patchmatchstereo翻译
  • Visual Basic 概述
  • redis项目知识体系
  • C++11(列表初始化、右值引用和移动语义)
  • 北京规划建设 杂志 官方网站多说与网站账号绑定
  • 网站建站外包公司产品做网站如何谁来维护价格
  • 电子商务网站开发文档济宁seo优化公司