11 Go语言的映射——map

Go语言的映射——map

[TOC]

  • 类似其它语言中的哈希表或者字典,以key-value形式存储数据
  • Key必须是支持==或!=比较运算的类型,不可以是函数、map或slice;value 可以是任意类型。
  • Map查找比线性搜索快很多,但比使用索引访问数据的类型慢100倍
  • Map使用make()创 建,支持 := 这种简写方式
  • make(map[keyType]valueType, cap),cap表示容量,可省略
  • 超出容量时会自动扩容,但尽量提供一个合理的初始值,预先申请内存,有助于提升性能
  • 使用len()获取元素个数
  • 键值对不存在时自动添加,使用delete()删除某键值对
  • 使用 for range 对map和slice进行迭代操作

Map介绍

go语言中的map是一种数据结构,用于存储一些列无序的键值对。map是一个无序的集合,因为它底层是一个hash表(散列表)。map的键只要支持==或!=比较运算的类型都可以,但是不可以是函数,map,slice等不能比较的。value可以是任意的类型。

1、Map 的创建

1.1 使用make函数

// 创建一个映射,键的类型是 string,值的类型是 int
dict := make(map[string]int)

make(map[keyType]valueType, cap),cap表示容量,可以在创建的时候指定一个合理初始的容量大小,这样就会申请一大块内存,避免在后续使用中频繁扩张浪费性能。比如:m := make(map[string]int, 1000)

1.2 使用字面值创建

// 创建一个映射,键和值的类型都是 string
// 使用两个键值对初始化映射
dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}

2、使用映射

2.1为映射赋值

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

2.1 未初始化的map,赋值报错,即 nil map

// 通过声明映射创建一个 nil 映射
var colors map[string]string
// 将 Red 的代码加入到映射
colors["Red"] = "#da1337"
Runtime Error:
panic: runtime error: assignment to entry in nil map

2.2 从map 中获取值,并判断键是否存在

由于go的多返回值,map获取值的时候,会返回值,和一个boolean的参数,表示成不成功,有没有,对不对。

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

// 获取键 Blue 对应的值
value, exists := colors["Blue"]// 这个键存在吗?
if exists {
    fmt.Println(value)
}
//当然了也可以直接用 类型的零值来判断----是一样的
// 获取键 Blue 对应的值
value := colors["Blue"]
// 这个键存在吗?
if value != "" {
    fmt.Println(value)
}

2.3 用range迭代map

// 创建一个映射,存储颜色以及颜色对应的十六进制代码
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)
}
//

range迭代和数组、slice 都一样,只不过这里返回的是map的键值对,而array ,slice返回的是索引和值

2.4 map中的delete函数

delete(map,key) 函数可以从map中删除指定key的键值对。这种方法只能用在映射存储的值都是非零值的情况

// 删除键为 Coral 的键值对
delete(colors, "Coral")
// 显示映射里的所有颜色
for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
}

2.5 map作为参数传递

和slice一样,都是引用类型,都是指向了底层数据结构。slice指向的是数组,map指向的是hash表。map在函数之间作为参数传递的时候,是进行map指针的拷贝,相对于指针来说是值拷贝,相对于底层来说是引用传递。 其实我觉得go所有的传递都是值传递,只不过有的值是值,有的值是指针。

所以,在函数中传递map,对map进行修改会对底层数据进行修改。

// removeColor 将指定映射里的键删除
func removeColor(colors map[string]string, key string) {
    delete(colors, key)
}
// 创建一个映射,存储颜色以及颜色对应的十六进制代码
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)
}
//输出结果
Key: AliceBlue Value: #F0F8FF
Key: Coral Value: #FF7F50
Key: DarkGray Value: #A9A9A9
Key: ForestGreen Value: #228B22

Key: AliceBlue Value: #F0F8FF
Key: DarkGray Value: #A9A9A9
Key: ForestGreen Value: #228B22

map的常见操作

m := map[string]int{
    "a": 1,
}
if v, ok := m["a"]; ok { // 判断 key 是否存在。
    println(v)
}
println(m["c"]) // 对于不存在的 key,直接返回 \0,不会出错。

m["b"] = 2 // 新增或修改。

delete(m, "c") // 删除。如果 key 不存在,不会出错。

println(len(m)) // 获取键值对数量。 cap ⽆效。

for k, v := range m { // 迭代,可仅返回 key。随机顺序返回,每次都不相同。
    println(k, v)
}

3、从map取出的value是一个拷贝,对其成员修改没有意义

type user struct{ name string }
m := map[int]user{     // 当 map 因扩张⽽重新哈希时,各键值项存储位置都会发⽣改变。 因此, map
    1: {"user1"},      // 被设计成 not addressable。 类似 m[1].name 这种期望透过原 value
}                     // 指针修改成员的⾏为⾃然会被禁⽌。
m[1].name = "Tom"     // Error: cannot assign to m[1].name

因为取出的是一个user实例的拷贝,不能直接对其成员修改,如果要实现,可以有两种方式

3.1完整的替换这个value

u := m[1]
u.name = "Tom"
m[1] = u // 替换 value。

3.2 使用指针

m2 := map[int]*user{
    1: &user{"user1"},
}
m2[1].name = "Jack" // 返回的是指针复制品。透过指针修改原对象是允许的。

相关推荐