Go 语言快速入门指南:第六篇 与数据为舞之映射

简介: 在我们学习汉字的时候,发现有一个生僻字的话,我们会使用字典。字典这种数据组织方式就是为了方便查询的操作的,那么 Go 语言中有没有这样的方式来存储数据呢?当然是有,maps。

在我们学习汉字的时候,发现有一个生僻字的话,我们会使用字典。字典这种数据组织方式就是为了方便查询的操作的,那么 Go 语言中有没有这样的方式来存储数据呢?当然是有,maps。


Go maps 类似于其他编程语言的哈希表,在 Python 中称为字典,Ruby 为散列,而 JavaScript 则被称为对象,PHP 是关联数组。


不像数组和切片,maps 的主要优点是它们可以使用任何数据类型作为索引,在这种情况下称为映射键或 key。


尽管 Go maps 不排除任何数据类型作为键,但要用作键的数据类型必须具有可比性,这意味着 Go 编译器必须能够区分一个键和另一个键,或者简单地说 ,映射的键必须支持 == 运算符。

映射

映射也是 Go 内置的数据结构,用于存储键值对的无序集合。


也被称为关联数组、哈希表字典。类似于查字典, 映射用于通过关键键查找关联的值。键是唯一的,键对应的值可以通过键来获取、更新或删除。 可以利用映射来检测一个键是否已经存在。值存储后,可以通过引用相关的键来调用映射的值。

映射的定义

以下是 Go 中映射的定义:

var x map[string] int


映射类型由关键字 map 表示,后跟括号中的类型,最后是类型。你可以创建一个空 map,并用 string 作为键,int 作为值,在 go 中可以用 make() 函数创建:

myMap = make(map[string] int)

或者指定一个 预先分配的空间,就像分配切片的容量一样:

myMap := make(map[int]string, 18)

这里的 string 就是键类型, int 就是值的类型,我们也可以按如下方式创建:

myMap := make(map[string]int)
myMap["小王"] = 17
myMap["小李"] = 19
myMap["老王"] = 51

也可以使用 map 字面量来创建一个带初始化键值对元素的映射::

myClass := map[string]int {
    "小王": 17,
    "小李": 19,
    "老张": 51,
}

映射取值


类似于数组和切片,同样可以使用中括号 [] 来访问映射,然后我们可以通过 myClass["小李"]myClass["老张"] 来取值,将会分别得到 18 和 50 的结果。

package main
import "fmt"
func main() {
    my_map := make(map[string]int)  // 创建一个从string到int的
    my_map["小李"] = 18
    my_map["老张"] = 50
    fmt.Println(my_map)
    fmt.Printf("老张今年%d岁.", my_map["老张"])
}

运行该代码,结果为:

map[小李:18 老张:50]
老张今年50岁.


如果程序中访问的键并不存在于 myClass 中,那么 Go 将会根据值的类型返回相应的零值作为结果,比如 myClass["张三"] 就会返回结果为“0”。

Tips: 正因为,当我们想尝试获取 maps 中不存在的键的值,最终会得到零,导致我们无法确定结果实际上是 0,还是因为没有这个值导致的值为 0。所以在 Go 语言中有 _, ok 的用法。

_, ok := myClass["张三"]
    if ok {
        fmt.Println("张三存在~")
    } else {
        fmt.Println("张三不存在!")
}

这个 ok 也不是必须这样命名,可以设置为其他非关键字 命名法,比如 age, found := myClass["张三"]。

映射遍历

for key, value := range myClass {
    fmt.Println(key, value)
}

映射删除

可以使用内置函数 delete 来从字典中根据键移除一个元素:

delete(ages, "老张") // 删除 ages["老张"]

映射排序

映射中元素的迭代顺序是不固定的,不同的实现方法会使用不同的散列算法,得到不同的元素顺序。如果需要按照某种顺序来遍历映射中的元素,可以显式的给键排序。

像上述的例子中,键是字符串类型,可以使用 sort 包中的 Strings 函数来进行键的排序:

package main
import (
    "fmt"
    "sort"
)
func main() {
    var names []string
    ages := map[string]int{
        "小李": 18,
        "老张": 30,
        "老罗": 45,
    }
    for name, age := range ages {
        fmt.Println(name, age)
    }
    fmt.Println("--- 排序后 ---")
    for name := range ages {
        names = append(names, name)
    }
    sort.Strings(names)
    for _, name := range names {
        fmt.Printf("%s\t%d\n", name, ages[name])
    }
}

运行后,得到结果:

老罗 45
小李 18
老张 30
--- 排序后 ---
小李  18
老张  30
老罗  45

映射是引用类型

映射也是引用类型。 将映射分配给新变量时,它们都引用相同的底层数据结构。 因此,一个变量更改,对另一个变量也会被相应的更改。 例子如下:

package main
import (
    "fmt"
)
func main() {
    var my_map = map[int]string{
        64: "new Zealand",
        3:  "Russia",
        44: "UK",
        61: "Australia",
        81: "Japan",
        91: "India",
    }
    fmt.Println("初始 map: ", my_map)
    // 赋值给新 map
    new_map := my_map
    // 新 map 中进行添加
    new_map[86] = "China"
    new_map[33] = "France"
    fmt.Println("new_map: ", new_map)
    fmt.Println("修改后的初始 map: \n", my_map)
}

运行结果:

初始 map:  map[3:Russia 44:UK 61:Australia 64:new Zealand 81:Japan 91:India]
new_map:  map[3:Russia 33:France 44:UK 61:Australia 64:new Zealand 81:Japan 86:China 91:India]
修改后的初始 map: 
 map[3:Russia 33:France 44:UK 61:Australia 64:new Zealand 81:Japan 86:China 91:India]

总结

映射比切片和数组更通用,但这种灵活性是有代价的:实现 Go 映射需要额外的空间。  映射非常方便,可以存储多种不同类型的数据,尤其当我们需要追求查询速度的时候,就该想到它。


映射是 Go 中键值对的无序集合。键在映射中是唯一的,但值可能不是。它被广泛使用,因为它提供了可以在键的帮助下检索、更新或删除的快速查找和值。


映射也称为关联数组、哈希表或字典。在 Go 中,您可以使用内置的 make() 函数初始化映射。它就会返回一个已初始化并可随时使用的映射。


可以使用 Go 编程语言中 for...range 循环的范围形式迭代映射。


在 Golang 中,映射是一个无序集合,因此,不能保证每次迭代时映射的迭代顺序都相同。因此,如果您多次运行任何程序,您将获得不同顺序的结果。


Maps 是 Golang 中的引用类型。 将映射分配给新变量时,它们都引用相同的底层数据结构。 因此,一个变量所做的更改,另一个变量相应会被更改。

相关文章
|
1天前
|
IDE Linux Go
记录一个go语言与IDE之间的问题
【7月更文挑战第1天】本文介绍在IDE中调试Go应用可能遇到的问题。当问题与IDE的自动完成有关,可以试着使用其他编辑器如Linux的vim是否无此问题。这可以验证表明IDE可能不完全兼容最新语言版本,建议使用无自动检测工具临时解决。
16 0
|
1天前
|
安全 Go
Go语言的iota关键字有什么用途?
**Go语言中的`iota`是常量生成器,用于在`const`声明中创建递增的常量。`iota`在每个新的`const`块重置为0,然后逐行递增,简化了枚举类型或常量序列的定义。例如,定义星期枚举:** ```markdown ```go type Weekday int const ( Sunday Weekday = iota // 0 Monday // 1 Tuesday // 2 ... ) ``` 同样,`iota`可用于定义不同组的常量,如状态码和标志位,保持各自组内的递增,提高代码可读性。
|
1天前
|
JSON 前端开发 JavaScript
Go怎么解析不定JSON数据?
在Go中处理不确定结构的JSON数据,可以使用`map[string]interface{}`来解析,它能适应各种JSON键值对,但需要类型检查。另一种方法是使用`json.RawMessage`保存原始JSON,之后按需解析。此外,`json.Number`用于处理任意精度的数字。当JSON字段类型未知时,可以先解码到`interface{}`并做类型断言。第三方库如gjson和jsonparser提供更灵活的解析选项。
|
3天前
|
JSON 算法 测试技术
在go语言中调试程序
【6月更文挑战第29天】Go语言内置`testing`包支持单元测试、基准测试和模糊测试。`go test`命令可执行测试,如`-run`选择特定测试,`-bench`运行基准测试,`-fuzz`进行模糊测试。
16 2
在go语言中调试程序
|
4天前
|
编译器 Go C++
必知的技术知识:go语言快速入门教程
必知的技术知识:go语言快速入门教程
|
5天前
|
编译器 Go 开发者
|
12天前
|
中间件 Go
go语言后端开发学习(三)——基于validator包实现接口校验
go语言后端开发学习(三)——基于validator包实现接口校验
|
12天前
|
存储 Go 开发工具
go语言后端开发学习(二)——基于七牛云实现的资源上传模块
go语言后端开发学习(二)——基于七牛云实现的资源上传模块
|
12天前
|
JSON 算法 Go
go语言后端开发学习(一)——JWT的介绍以及基于JWT实现登录验证
go语言后端开发学习(一)——JWT的介绍以及基于JWT实现登录验证
|
2月前
|
缓存 负载均衡 网络协议
使用Go语言开发高性能服务的深度解析
【5月更文挑战第21天】本文深入探讨了使用Go语言开发高性能服务的技巧,强调了Go的并发性能、内存管理和网络编程优势。关键点包括:1) 利用goroutine和channel进行并发处理,通过goroutine池优化资源;2) 注意内存管理,减少不必要的分配和释放,使用pprof分析;3) 使用非阻塞I/O和连接池提升网络性能,结合HTTP/2和负载均衡技术;4) 通过性能分析、代码优化、缓存和压缩等手段进一步提升服务性能。掌握这些技术能帮助开发者构建更高效稳定的服务。