34

11 Go语言的映射——map

 5 years ago
source link: https://studygolang.com/articles/18647?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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" // 返回的是指针复制品。透过指针修改原对象是允许的。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK