Go语言基础之map

map 是 go 的一种 Key-Value 类型的数据结构,其内部使用散列表(hash)实现。

map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。

map声明语法为map[K]V,其中K和V分别对应key和value。map中所有的key都有相同的类型,所有的value也有着相同的类型,但是key和value之间可以是不同的数据类型。

map中的K对应的key必须是支持==比较运算符的数据类型,比如 整数,浮点数,指针,数组,结构体,接口等。 而不能是 函数,字典,切片这些类型,可以通过测试key是否相等来判断是否已经存在。

1. 介绍

  1. map 是一种元素对pair(key-value)的无序集合,类似其他语言的哈希表或字典。是引用类型。

  2. 未初始化的 map 的值是 nil,使用函数 len() 可以获取 map 中 pair 的数目。

  3. map查找比线性搜索快很多,但比使用索引访问数据的类型慢100倍;

  4. map使用make([keyType] valueType,cap)创建,支持:=这种简写方式。cap表示容量,可省略;超出容量时会自动扩容,但尽量提供一个合理的初始值。

mapname 为 map 的变量名
keytype 为键类型
valuetype 是键对应的值类型

var mapname map[keytype]valuetype

var m map[string]int

2. 声明&创建

var 变量名称 map[key_type]value_type

注意声明map类型是不会分配内存的。初始化需要make,才会分配内存。

普通声明

可以用map字面值的语法创建map,同时进行数据的初始化

将音阶和对应的音频映射

noteFrequency := map[string]float32 {
"C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83,
"G0": 24.50, "A0": 27.50, "B0": 30.87, "A4": 440}

make函数

内置的make函数可以创建一个map:

map 可以根据新增的 key-value 动态的伸缩,因此它不存在固定长度或者最大限制,但是也可以选择标明 map 的初始容量 cap。

m := make(map[string]int, 10)

fmt.Println(m, len(m)) // [] 0

当 map 增长到容量上限的时候,如果再增加新的 key-value,map 的大小会自动加 1,所以出于性能的考虑,对于大的 map 或者会快速扩张的 map,即使只是大概知道容量,也最好先标明。

用 slice 作为map 的值

mp1 := make(map[int][]int)
mp2 := make(map[int]*[]int)

3. map的遍历

遍历不保证顺序,如果需要顺序,则需要手动对key排序。

Go语言中使用for range遍历map。

func main() {
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
for k, v := range scoreMap {
fmt.Println(k, v) // key & value
}
}

但我们只想遍历key的时候,可以按下面的写法:

// 只遍历key可以省略value;只遍历value使用匿名变量存放key
func main() {
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
for k := range scoreMap {
fmt.Println(k)
}
}

4. 查找

Map中的元素通过key对应的下标语法访问:

value := m[key]

eg:

func main() {
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
value := scoreMap["小明"]
fmt.Println(value)
}

5. 判断某个键是否存在

若果key值不存在,则得到ValueType对应类型的零值。

Go语言中有个判断map中键是否存在的特殊写法,格式如下:

value, ok := map[key] // value和是否存在的布尔值

eg:

func main() {
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
// 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值
v, ok := scoreMap["张三"]
if ok {
fmt.Println(v)
} else {
fmt.Println("查无此人")
}
}

6. 删除

Go语言提供了一个内置函数 delete(),用于删除map内的元素。

使用delete()内建函数从map中删除一组键值对,delete()函数的格式如下:

delete(map, key)

其中,

  • map:表示要删除键值对的map

  • key:表示要删除的键值对的键

  • 删除不存在的key值或map为nil 不做任何操作

示例代码如下:

func main(){
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
delete(scoreMap, "小明")//将小明:100从map中删除
for k,v := range scoreMap{
fmt.Println(k, v)
}
}

清空

  1. Go语言中并没有为 map 提供任何清空所有元素的函数。
  2. 清空 map 的唯一办法就是重新 make 一个新的 map,不用担心垃圾回收的效率,Go语言中的并行垃圾回收效率比写一个清空函数要高效的多。

7. 获取map中元素的个数

len(map)

8. 按照指定顺序遍历map

原理:把map的key值append进入一个切片,对切片排序完成对map的排序。

func main() {
rand.Seed(time.Now().UnixNano()) //初始化随机数种子(当前时间的ns)???

var scoreMap = make(map[string]int, 200)
for i := 0; i < 100; i++ {
key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
value := rand.Intn(100) //生成0~99的随机整数
scoreMap[key] = value
}
//取出map中的所有key存入切片keys
var keys = make([]string, 0, 200)
for key := range scoreMap {
keys = append(keys, key)
}
//对切片进行排序
sort.Strings(keys)
//按照排序后的key遍历map
for _, key := range keys {
fmt.Println(key, scoreMap[key])
}
}

9. 元素为map类型的切片

下面的代码演示了切片中的元素为map类型时的操作:

func main() {
var mapSlice = make([]map[string]string, 3)// 1. 类型为map[string]string的切片
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)// 2. 此时value都是map类型的零值空map
}
fmt.Println("after init")
// 3. 对切片中的map元素进行初始化-把切片元素赋值为map进行初始化
mapSlice[0] = make(map[string]string, 10)
mapSlice[0]["name"] = "小王子"// 4. 修改下标为0的map
mapSlice[0]["password"] = "123456"
mapSlice[0]["address"] = "沙河"
// 此时切片为:[map[address:沙河 name:小王子 password:123456] map[] map[]]
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
}

10. 值为切片类型的map

下面的代码演示了map中值为切片类型的操作:

func main() {
var sliceMap = make(map[string][]string, 3)// map
fmt.Println(sliceMap)
fmt.Println("after init")
key := "中国"
value, ok := sliceMap[key]
if !ok {
value = make([]string, 0, 2) // 切片
}
value = append(value, "北京", "上海")
sliceMap[key] = value
fmt.Println(sliceMap)
}

参考感谢
Go语言基础之map · 语雀 (yuque.com)
04.map · 语雀 (yuque.com)
数组,切片,以及 Map · 语雀 (yuque.com)
map · 语雀 (yuque.com)