脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Go语言映射内部实现及基础功能实战

Go语言映射内部实现及基础功能实战

2022-09-08 11:23山河已无恙 Golang

这篇文章主要为大家介绍了Go语言映射的内部实现和基础功能实战,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

Go语言映射内部实现及基础功能实战

写在前面

嗯,学习GO,所以有了这篇文章博文内容为《GO语言实战》读书笔记之一主要涉及映射相关知识

你要爱就要像一个痴情的恋人那样去爱,像一个忘死的梦者那样去爱,视他人之疑目如盏盏鬼火,大胆去走你的夜路。——史铁生《病隙碎笔》

映射的内部实现和基础功能

映射是一种数据结构,是用于存储一系列无序的键值对。类比Java里的Map,Python里的字典,可以理解为以哈希值做索引,期望索引可以在一定的连续内存范围内的类似数组的数据结构。

映射里基于键来存储值。映射功能强大的地方是,能够基于键快速检索数据。键就像索引一样,指向与该键关联的值。

内部实现

映射是一个集合,可以使用类似处理数组和切片的方式迭代映射中的元素。但映射是无序的集合,无序的原因是映射的实现使用了散列表.

映射的散列表包含一组桶。

在存储、删除或者查找键值对的时候,所有操作都要先选择一个桶。把操作映射时指定的键传给映射的散列函数,就能选中对应的桶。

这个散列函数的目的是生成一个索引,这个索引最终将键值对分布到所有可用的桶里。对 Go 语言的映射来说,生成的散列键的一部分,具体来说是低位(LOB),被用来选择桶。

Go语言映射内部实现及基础功能实战

桶的内部实现。映射使用两个数据结构来存储数据,

第一个是数组,内部存储用于选择桶的散列键的高八位值。用于区分每个键值对要存在桶里的那一项。第二个是字节数组,用于存储键值对。该字节数组先依次存储了这个桶里所有的键,之后依次存储了这个桶里所有的值。实现这种键值对的存储方式目的在于减少每个桶所需的内存。

映射存储的增加,索引分布越均匀,访问键值对的速度就越快,随着映射存储的增加,索引分布越均匀,访问键值对的速度就越快。映射通过合理数量的桶来平衡键值对的分布

创建和初始化

Go 语言中有很多种方法可以创建并初始化映射,可以使用内置的make 函数,也可以使用映射字面量。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import (
    "fmt"
)
func main() {
    // 创建一个映射,键的类型是 string,值的类型是 int
    dict := make(map[string]int)
    // 创建一个映射,键和值的类型都是 string
    // 使用两个键值对初始化映射
    dict_ := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
    fmt.Println(dict)
    fmt.Print(dict_)
}
======
map[]
map[Orange:#e95a22 Red:#da1337]

创建映射时,更常用的方法是使用映射字面量。映射的初始长度会根据初始化时指定的键值对的数量来确定。

映射的键可以是任何值。这个值的类型可以是内置的类型,也可以是结构类型,只要这个值可以使用==运算符做比较

切片、函数以及包含切片的结构类型由于具有引用语义,不能作为映射的键,使用这些类型会造成编译错误

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import (
    "fmt"
)
func main() {
    // 创建一个映射,使用字符串切片作为映射的键
    dict := map[[]string]int{}
    fmt.Println(dict)
}
====
[Running] go run "d:\GolandProjects\code-master\demo\hello.go"
# command-line-arguments
demo\hello.go:10:45: duplicate key "Red" in map literal
    previous key at demo\hello.go:10:28
[Done] exited with code=2 in 0.902 seconds

声明一个存储字符串切片的映射

?
1
2
// 创建一个映射,使用字符串切片作为值
dict := map[int][]string{}

使用映射

键值对赋值给映射,是通过指定适当类型的键并给这个键赋一个值来完成的

为映射赋值

?
1
2
3
4
// 创建一个空映射,用来存储颜色以及颜色对应的十六进制代码
colors := map[string]string{}
// 将 Red 的代码加入到映射
colors["Red"] = "#da1337"

可以通过声明一个未初始化的映射来创建一个值为nil的映射,不能用于存储键值对.

?
1
2
3
4
// 创建一个空映射,用来存储颜色以及颜色对应的十六进制代码
colors := map[string]string{}
// 将 Red 的代码加入到映射
colors["Red"] = "#da1337"

从映射取值时有两个选择:

第一个选择是,可以同时获得值,以及一个表示这个键是否存在的标志,

从映射获取值并判断键是否存在

?
1
2
3
4
5
6
// 获取键 Blue 对应的值
value := colors["Blue"]
// 这个键存在吗?
if value != "" {
fmt.Println(value)
}

另一个选择是,只返回键对应的值,然后通过判断这个值是不是零值来确定键是否存在

从映射获取值,并通过该值判断键是否存在

?
1
2
3
4
5
6
// 获取键 Blue 对应的值
value := colors["Blue"]
// 这个键存在吗?
if value != "" {
fmt.Println(value)
}

在Go语言里,通过键来索引映射时,即便这个键不存在也总会返回一个值。在这种情况下,返回的是该值对应的类型的零值

迭代映射里的所有值和迭代数组或切片一样,使用关键字 range

使用range 迭代映射

?
1
2
3
4
5
6
7
8
9
10
11
// 创建一个映射,存储颜色以及颜色对应的十六进制代码colors := map[string]string{<!--{C}%3C!%2D%2D%20%2D%2D%3E-->"AliceBlue": "#f0f8ff","Coral": "#ff7F50","DarkGray": "#a9a9a9","ForestGreen": "#228b22",}// 显示映射里的所有颜色for key, value := range colors {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->fmt.Printf("Key: %s Value: %s\n", key, value)}// 创建一个映射,存储颜色以及颜色对应的十六进制代码
colors := map[string]string{
"AliceBlue": "#f0f8ff",
"Coral": "#ff7F50",
"DarkGray": "#a9a9a9",
"ForestGreen": "#228b22",
}
// 显示映射里的所有颜色
for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
}

想把一个键值对从映射里删除,就使用内置的delete 函数

从映射中删除一项

?
1
2
3
4
5
6
// 删除键为 Coral 的键值对delete(colors, "Coral")// 显示映射里的所有颜色for key, value := range colors {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->fmt.Printf("Key: %s Value: %s\n", key, value)}// 删除键为 Coral 的键值对
delete(colors, "Coral")
// 显示映射里的所有颜色
for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
}

在函数间传递映射

在函数间传递映射并不会制造出该映射的一个副本。实际上,当传递映射给一个函数,并对这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改,这个特性和切片类似,保证可以用很小的成本来复制映射

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package mainimport ("fmt")func main() {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->// 创建一个映射,存储颜色以及颜色对应的十六进制代码colors := map[string]string{<!--{C}%3C!%2D%2D%20%2D%2D%3E-->"AliceBlue": "#f0f8ff","Coral": "#ff7F50","DarkGray": "#a9a9a9","ForestGreen": "#228b22",}// 显示映射里的所有颜色for key, value := range colors {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->fmt.Printf("Key: %s Value: %s\n", key, value)}fmt.Println("调用函数来移除指定的键")// 调用函数来移除指定的键removeColor(colors, "Coral")// 显示映射里的所有颜色for key, value := range colors {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->fmt.Printf("Key: %s Value: %s\n", key, value)}}// removeColor 将指定映射里的键删除func removeColor(colors map[string]string, key string) {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->delete(colors, key)}package main
 
import (
    "fmt"
)
func main() {
    // 创建一个映射,存储颜色以及颜色对应的十六进制代码
    colors := map[string]string{
        "AliceBlue":   "#f0f8ff",
        "Coral":       "#ff7F50",
        "DarkGray":    "#a9a9a9",
        "ForestGreen": "#228b22",
    }
    // 显示映射里的所有颜色
    for key, value := range colors {
        fmt.Printf("Key: %s Value: %s\n", key, value)
    }
    fmt.Println("调用函数来移除指定的键")
    // 调用函数来移除指定的键
    removeColor(colors, "Coral")
    
    // 显示映射里的所有颜色
    for key, value := range colors {
        fmt.Printf("Key: %s Value: %s\n", key, value)
    }
}
// removeColor 将指定映射里的键删除
func removeColor(colors map[string]string, key string) {
    delete(colors, key)
}
?
1
2
3
4
5
6
7
8
9
10
[Running] go run "d:\GolandProjects\code-master\demo\hello.go"
Key: Coral Value: #ff7F50
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
Key: AliceBlue Value: #f0f8ff
调用函数来移除指定的键
Key: AliceBlue Value: #f0f8ff
Key: DarkGray Value: #a9a9a9
Key: ForestGreen Value: #228b22
[Done] exited with code=0 in 1.419 seconds

映射的增长没有容量或者任何限制。同时内置函数 len可以用来获取切片或者映射的长度。但是内置函数 cap只能用于切片。

Go语言映射内部实现及基础功能实战

以上就是Go语言映射内部实现及基础功能实战的详细内容,更多关于Go语言映射内部实现和基础功能的资料请关注服务器之家其它相关文章!

原文链接:https://liruilong.blog.csdn.net/article/details/123414901

延伸 · 阅读

精彩推荐
  • Golanggolang顺时针打印矩阵的方法示例

    golang顺时针打印矩阵的方法示例

    这篇文章主要介绍了golang顺时针打印矩阵的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    ifcoder4942020-05-22
  • Golang如何在Go中将[]byte转换为io.Reader

    如何在Go中将[]byte转换为io.Reader

    本文主要介绍了如何在Go中将[]byte转换为io.Reader,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    yongxinz7682022-01-26
  • Golanggolang 手写贪吃蛇示例实现

    golang 手写贪吃蛇示例实现

    这篇文章主要为大家介绍了golang 手写贪吃蛇示例实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    黑胡子Z5262022-07-21
  • GolangGo语言字典(map)用法实例分析【创建,填充,遍历,查找,修改,删除】

    Go语言字典(map)用法实例分析【创建,填充,遍历,查找,修改,删除】

    这篇文章主要介绍了Go语言字典(map)用法,结合实例形式较为详细的分析了Go语言字典的创建、填充、遍历、查找、修改、删除等操作相关实现技巧,需要的朋...

    52PHP4862020-05-05
  • GolangGolang如何交叉编译各个平台的二进制文件详解

    Golang如何交叉编译各个平台的二进制文件详解

    这篇文章主要给大家介绍了关于Golang如何交叉编译各个平台的二进制文件的相关资料,并介绍了golang如何让编译生产的二进制文件变小,对大家的学习或者...

    路过麦田5222020-05-18
  • GolangGolang 语言map底层实现原理解析

    Golang 语言map底层实现原理解析

    这篇文章主要介绍了Golang 语言map底层实现原理解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    程序员阿俊8752021-02-21
  • GolangGO语言开发环境搭建过程图文详解

    GO语言开发环境搭建过程图文详解

    这篇文章主要介绍了GO语言开发环境搭建过程图文详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    给你骨质唱疏松7762021-03-27
  • Golang详解go语言中sort如何排序

    详解go语言中sort如何排序

    我们的代码业务中很多地方需要我们自己进行排序操作,本文主要介绍了详解go语言中sort如何排序,文中通过示例代码介绍的非常详细,具有一定的参考价...

    Zhan-LiZ11882022-09-05