go语言map映射
GO语言Map映射
GO语言Map 映射
Map 映射 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
值的类型 | 值的数量 | 值的索引 | |
---|---|---|---|
数组: | 相同 | 固定 | 下标 |
切片: | 相同 | 动态 | 下标 |
结构体: | 不相同 | 固定 | 属性名 |
映射: | 相同 | 动态 | key |
映射的实现
因为映射也是一个数据集合,所以,也可以使用类似处理数组和切片的方式来迭代映射中的元素。但 映射是无序集合,所以即使以同样的顺序保存键值对,每次迭代映射时,元素的顺序也可能不一样。
无序的原因是映射的本质使用了 散列表
map 在底层使用哈希(hash)来实现的,在C:\Program Files\Go\src\hash\maphash\maphash.go ,map是一个hash数组列表,由一个个bucket 组成
每一个元素都被称为bucket的结构体,每一个bucket 可以保存8个键值对,所有元素被hash算法填入到数组的bucket中,bucket填满后,将通过 一个overflow指针来扩展一个bucket,从而来形成链表,以此来解决hash冲突的问题。map就是一个bucket指针型的一堆数组
定义 Map
可以使用内建函数 make 也可以使用 map 关键字来定义 Map:
复制//使用make 函数,创建一个映射,键的类型是string,值的类型是int
dict := make(map[string]int)
//创建一个映射,键值类型都是string,并进行初始化
teacher := map[string]string{"zhangsan":"Chinese","lisi":"English"}
//如果仅仅声明map,而不进行 初始化,那么就会创建一个空映射,空映射不能存放键值对.所以
//方法一:
var student map[string]string
student = make(map[string]string) //初始化
//方法二:
var student map[string]string = make(map[string]string)
如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对
映射的 键的可以是任何类型内置类型或者结构体都可以,需要确定这个值可以使用 == 运算符做比较。但是如切片,函数,这种引用类型的可以作为映射的键
映射的 值 可以是任何类型
元素赋值与获取元素值
指定适当的类型键,并给这个键赋一个值就完成了映射的键值对赋值
赋值直接定义键值对,自动添加。键名必须唯一 .如果 键名重复,则会修改之前的值
如果想象获取元素的值,使用键名获取
复制//赋值
package main
import "fmt"
func main() {
colors := map[string]string{}
colors["red"] = "红色"
colors["blue"] = "蓝色"
fmt.Println(colors)
//键名重复,则修改键的值
colors["red"] = "红"
fmt.Println(colors)
}
//输出结果:
map[blue:蓝色 red:红色]
map[blue:蓝色 red:红]
复制//通过键名,获取对应的值
package main
import "fmt"
func main() {
colors := map[string]string{}
colors["red"] = "红色"
colors["blue"] = "蓝色"
//使用定义的映射,然后加上下标,下标为键名
fmt.Println(colors["red"])
fmt.Println(colors["blue"])
}
//输出结果:
红色
蓝色
查找与遍历、
查找
从映射去值时,有两种方式。
第一种方式是:获得值以及一个表达这个值是否存在的标志
复制package main
import "fmt"
func main() {
colors := map[string]string{}
colors["red"] = "红色"
colors["blue"] = "蓝色"
//value 是red 对应的值。 exists 是布尔类型,判断键是否存在
value, exists := colors["red"]
fmt.Println(value, exists)
if exists {
fmt.Println("键存在")
}
//重新赋值value和exists。
//value 是black 对应的值,如果black不存在,则返回string类型的默认值,即 空
value, exists = colors["black"]
fmt.Println(value, exists)
if !exists {
fmt.Println("键不存在")
}
}
红色 true
键存在
false
键不存在
//输出结果:
第二种方式是,只返回键对应的值,在判断这个值是否为0值(int类型),或者是否为空值(string类型)。以此来判断键是否存在。这种方式只能用在映射存的的值都是非0值或者非空值
复制package main
import "fmt"
func main() {
colors := map[string]string{}
colors["red"] = "红色"
colors["blue"] = "蓝色"
//获取red 键对应的值。如果red键不存在,则结果为对应数值类型的默认值。string 类型默认为空
value := colors["red"]
//判断这个键是否存在
if value != "" {
fmt.Println("键存在")
fmt.Println(value)
}
}
//输出结果:
键存在
红色
遍历
通过使用range 可以迭代映射里的所有值
复制package main
import "fmt"
func main() {
colors := map[string]string{}
colors["red"] = "红色"
colors["blue"] = "蓝色"
//使用range 遍历所有信息
for key, value := range colors {
fmt.Printf("key:%s,value:%s \n", key, value)
}
}
//输出结果:
key:red,value:红色
key:blue,value:蓝色
delete函数删除集合的元素
复制package main
import "fmt"
func main() {
colors := map[string]string{}
colors["red"] = "红色"
colors["blue"] = "蓝色"
colors["yellow"] = "黄色"
colors["green"] = "绿色"
fmt.Println("删除前:", colors)
//删除元素
delete(colors, "red")
fmt.Println("删除后:", colors)
}
//输出结果:
删除前: map[blue:蓝色 green:绿色 red:红色 yellow:黄色]
删除后: map[blue:蓝色 green:绿色 yellow:黄色]
<br<
将映射传递给函数
在函数键传递映射并不会制造出该映射的副本。当传递映射给函数并对这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改
复制package main
import "fmt"
func main() {
colors := map[string]string{}
colors["red"] = "红色"
colors["blue"] = "蓝色"
colors["yellow"] = "黄色"
colors["green"] = "绿色"
fmt.Println("修改前:", colors)
//将映射作为值,传递给函数
test(colors)
fmt.Println("修改后:", colors)
}
func test(m map[string]string) {
m["black"] = "黑色"
}
//输出结果:
修改前: map[blue:蓝色 green:绿色 red:红色 yellow:黄色]
修改后: map[black:黑色 blue:蓝色 green:绿色 red:红色 yellow:黄色]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现