Go语言还未入门就放弃之映射map

概览

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
通过 key 在 map 中寻找值是很快的,比线性查找快得多,但是仍然比从数组和切片的索引中直接读取要慢 100 倍;所以如果你很在乎性能的话还是建议用切片来解决问题。
key 可以是任意可以用 == 或者 != 操作符比较的类型,比如 string、int、float。所以数组、切片不能作为 key。含有数组切片的结构体不能作为 key,只包含内建类型的 struct 也可以作为 key ,但是指针和接口类型可以。

声明和初始化

  • dict := make(map[string]int) 创建一个映射,键的类型是 string,值的类型是 int
  • dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"} 创建一个映射,键和值的类型都是 string,使用两个键值对初始化映射
  • var colors map[string]string 通过声明映射创建一个 nil 映射,注意:nil 映射不能用于存储键值对。这点跟切片不一样,nil 切片可以append元素。
  • colors := map[string]string{} 创建一个空映射,用来存储颜色以及颜色对应的十六进制代码

使用映射

  • colors["Red"] = "#f00" 给映射赋值
  • delete(colors, "Red") 从映射中删除一项,key 不存在,该操作不会产生错误。
  • 从映射获取值并判断键是否存在

    1
    2
    3
    4
    5
    if value, exists := colors["Red"]; exists {
    fmt.Println(value)
    } else {
    fmt.Println("value not exists")
    }
  • 迭使用 range 迭代映射

    1
    2
    3
    for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
    }

在函数间传递映射

在函数间传递映射并不会制造出该映射的一个副本。当传递映射给一个函数,并对这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改。map 传递给函数的代价很小:在 32 位机器上占 4 个字节,64 位机器上占 8 个字节,无论实际上存储了多少数据。

一对多

一个 key 只能对应一个 value,而 value 又是一个原始类型,那么如果一个 key 要对应多个值怎么办。可以将值设为切片类型。如:

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
package main

import (
"fmt"
)

type M map[string]interface{}

func main() {
mapSlice := make(M)
list := []M{M{"1": "12"}, M{"1": "123"}, M{"2": "1234"}}
for _, oneM := range list {
for key, value := range oneM {
if ik, ok := mapSlice[key].([]interface{}); ok { //ik为mapSlice[key]的拷贝
fmt.Printf("0 %p\n", &ik)
ik = append(ik, value) //此时ik切片指向的底层数组的内存地址已经发生的变化,ik本身的地址并未变化
fmt.Printf("0 %p\n", &ik)
mapSlice[key] = ik //所以这里需要赋值
} else {
tmp := []interface{}{value}
mapSlice[key] = tmp
}
}
}
fmt.Printf("%#v", mapSlice)
}

您的支持将鼓励我继续创作!
0%