map 是 key-value 类型数据结构, 读作 (哈希表, 字典), 是一堆未排序的键值对集合.
map 是引用类型, 使用 make 函数或者初始化表达式创建.
map 的 key 必须是支持相等运算符 ==,!= 的类型, 如 int,bool,channel,string,pointer,array,sruct,interface.
通常 map 的 key 是 int,string
map 的 value 可以是任意类型, 没有限制, 通常是 int,float,string,struct
2. map 声明
- package main
- import "fmt"
- func main() {
- /*
- map 声明语法
- var 变量名 map[keytype]valuetype
- var m1 map[string]string
- var m2 map[int]string
- var m3 map[int]map[string]string//map 的 value 又是 map
- 注意 map 声明不会分配内存, 必须 make 初始化才可以使用
- */
- // 声明 map 方式一
- //make 函数可以合理申请一大块内存, 避免后续扩张时性能问题
- var m1 map[string]string
- // 标注 map 的初始容量为 10
- m1 = make(map[string]string, 10)
- m1["一号"] = "大狗子"
- m1["二号"] = "二狗子"
- fmt.Println(m1)
- // 声明方式二
- m2 := make(map[string]string)
- m2["男"] = "小黑"
- m2["女"] = "小女"
- fmt.Println(m2)
- // 声明方式三
- m3 := map[string]string{
- "坦克": "德玛西亚",
- "射手": "伊泽瑞尔",
- "辅助": "星女",
- }
- m3["打野"] = "赵信"
- fmt.Println(m3)
- }
3. map 增删改查
访问不存在的键值, 默认返回零值, 不会引发错误.
推荐使用 ok-idiom 模式, 如: val, ok := m1["k4"]
- package main
- import "fmt"
- func main() {
- m1 := map[string]string{"k1": "v1", "k2": "v2"}
- fmt.Printf("m1 值:%v\n", m1)
- //map 插入值
- m1["k3"] = "v3"
- fmt.Printf("插入后 m1 值:%v\n", m1)
- //map 修改值
- m1["k1"] = "v11111"
- fmt.Printf("修改 k1 值后:%v\n", m1)
- //map 查找值
- val, ok := m1["k4"]
- if ok {
- fmt.Printf("k4 的值是:%v\n", val)
- }
- // 长度: 获取键值对数量
- m1Len := len(m1)
- fmt.Printf("m1 长度:%v\n", m1Len)
- // 判断 key 是否存在
- if val, ok := m1["k4"]; !ok {
- fmt.Printf("此 key 不存在 \ n")
- } else {
- fmt.Printf("此 key 的值:%v\n", val)
- }
- // 删除 map 的 key, 如 key 不存在, delete 不进行操作
- //delete 函数按指定的键, 将元素从映射中删除
- // 一次性删除所有 key 可以遍历下, 逐个删除
- // 也可以重新 make 新 map, 让原本 map 被 gc 回收
- if _, ok := m1["k3"]; ok {
- delete(m1, "k3")
- fmt.Printf("已删除 m1 中的 k3\n")
- } else {
- fmt.Printf("无法删除, 此 key 不存在")
- }
- fmt.Printf("此时 m1 的值:%v\n", m1)
- }
4. map 遍历
使用 for-range 结构遍历
- package main
- import "fmt"
- func main() {
- // 循环性生成 10 个 key 的 map
- m1 := make(map[int]int)
- for i := 0; i < 10; i++ {
- m1[i] = i + 1
- fmt.Printf("m1 的 key:%v value:%v\n", i, m1[i])
- }
- fmt.Println(m1)
- fmt.Println("-- 分割线 --")
- // 循环遍历 map 的值
- for k, v := range m1 {
- fmt.Printf("m1 的 key:%v m1 的值 %v\n", k, v)
- }
- }
遍历复杂 map
map 的 value 又是 map
- package main
- import "fmt"
- func main() {
- //make 初始化第一层 map, 分配内存
- stuMap := make(map[string]map[string]string)
- // 第二层 map 初始化
- stuMap["stu01"] = make(map[string]string)
- stuMap["stu01"]["名字"] = "大狗子"
- stuMap["stu01"]["年纪"] = "18"
- // 切记, map 必须 make 后方可使用
- stuMap["stu02"] = make(map[string]string)
- stuMap["stu02"]["名字"] = "二麻子"
- stuMap["stu02"]["年纪"] = "17"
- fmt.Println(stuMap)
- // 取出所有学生的信息
- for k, v := range stuMap {
- fmt.Printf("k 值是学生:%v v 值是学生信息:%v\n", k, v)
- //k1 是键, v1 是值
- for k1, v1 := range v {
- fmt.Printf("\tk1:%v v1:%v\n", k1, v1)
- }
- fmt.Println()
- }
- }
5. map 切片
声明一个切片 (slice), 并且这个切片的类型是 map, 这就被称作 slice of map,map 切片, 这样 map 的个数就可以动态变化了.
- package main
- import "fmt"
- func main() {
- // 声明 map 切片,
- // 默认值 [map[] map[] map[] map[] map[]]
- sliceMap := make([]map[string]string, 5)
- for i := 0; i < 5; i++ {
- //map 必须初始化再用, 遍历初始化
- sliceMap[i] = make(map[string]string)
- }
- sliceMap[0]["名字"] = "张飞"
- sliceMap[1]["性别"] = "不男不女"
- sliceMap[2]["体重"] = "三百斤"
- fmt.Println(sliceMap)
- fmt.Printf("容量:%v, 长度:%v\n", cap(sliceMap), len(sliceMap))
- // 动态扩容 map 切片, 用 append 函数
- newSliceMap := map[string]string{
- "姓名": "狗子",
- "爱好": "吃包子",
- }
- //append 函数进行切片扩容, 动态增加
- sliceMap = append(sliceMap, newSliceMap)
- fmt.Println(sliceMap)
- fmt.Printf("容量:%v, 长度:%v\n", cap(sliceMap), len(sliceMap))
- }
6. map 排序
map 默认是无序的, 每次遍历都是不同的结果
- package main
- import "fmt"
- func main() {
- // 无须的 map
- m1 := make(map[int]int)
- for i := 0; i < 10; i++ {
- m1[i] = i + 1
- }
- // 遍历结果无序
- for k, v := range m1 {
- fmt.Println(k, v)
- }
- }
通过索引排序取值
- package main
- import "fmt"
- func main() {
- m1 := map[int]string{
- 1: "红孩儿",
- 2: "孙悟空",
- 3: "银角大王",
- 4: "金角大王",
- }
- // 无序
- // for k, v := range m1 {
- // fmt.Println(k, v)
- // }
- // 通过索引, 有序取值
- for i := 1; i <= len(m1); i++ {
- fmt.Println(i, m1[i])
- }
- }
sort 包排序
golang 没有针对 map 的 key 排序的方法.
必须先对 key 排序, 然后根据 key 值就可以输出排序后的结果
调用 sort 包函数进行排序
- sort.Strings
- sort.Ints
- package main
- import (
- "fmt"
- "sort"
- )
- func main() {
- // 定义一个 m map 变量
- m := map[string]string{"q": "q", "w": "w", "e": "e", "r": "r", "t": "t", "y": "y"}
- fmt.Println(m)
- // 定义一个 string 类型切片
- var slice []string
- // 循环遍历 map, 取出所有的 key 和 value
- for k, _ := range m {
- // 循环将 key 添加到切片中
- slice = append(slice, k)
- }
- fmt.Printf("切片 slice 值 : %v\n", slice)
- // 调用排序包, 对切片进行排序, 按照字母顺序排序
- sort.Strings(slice[:])
- fmt.Printf("排序后 切片 slice 值 : %v\n", slice)
- for _, v := range slice {
- fmt.Printf("排序后 m[%v]=%v\n", v, m[v])
- }
- }
7. map 使用细节
1)map 是引用类型, 遵循引用类型传递的机制, 在函数接收 map 参数, 对 map 修改是直接操作原本的 map.
- package main
- import "fmt"
- func modify(m map[string]string) {
- m["名字"] = "狗子"
- }
- func main() {
- //map 是引用类型, 遵循引用引用类型传递
- m1 := make(map[string]string)
- m1["名字"] = "傻子"
- m1["年纪"] = "十八"
- fmt.Println(m1)
- modify(m1) // 直接对 m1 进行修改, 说明是引用类型
- fmt.Println(m1)
- }
2)map 可以自动扩容, 动态增长.
- package main
- import "fmt"
- func main() {
- // 初始化 m1, 限制容量 3
- m1 := make(map[int]int, 3)
- for i := 0; i < 10; i++ {
- m1[i] = i + i
- }
- fmt.Println(m1)
- fmt.Printf("m1 元素个数:%v", len(m1))
- }
3)map 的 value 也可以是 struct 类型, 适合更复杂的数据
- package main
- import "fmt"
- type Stu struct {
- Name string
- Age int
- Address string
- }
- func main() {
- //map 的 value 可以为更复杂的 struct 结构体类型
- //map 的 key 是学号
- //map 的 value 是结构体 {姓名, 年纪, 住址}
- students := make(map[int]Stu, 10)
- // 初始化结构体, 不需要填写 key, 顺序 value 即可
- stu1 := Stu{"alex", 1000, "沙河"}
- stu2 := Stu{"武沛奇", 999, "于辛庄"}
- students[1] = stu1
- students[2] = stu2
- fmt.Println(students)
- // 遍历 map, 取出学生信息
- for k, v := range students {
- fmt.Printf("学生编号 %v\n", k)
- fmt.Printf("学生姓名 %v\n", v.Name)
- fmt.Printf("学生年纪 %v\n", v.Age)
- fmt.Printf("学生住址 %v\n", v.Address)
- fmt.Println("--------")
- }
- }
4) 函数 len 返回键值对数量, cap 不适用 map 类型.
5) 因内存访问安全和哈希算法等因素, 字典设计是 not addressable, 不得直接修改 value 成员 (struct 或 array)
6)mymap["age"]+=1 此代码报错
7)mymap["age"]++ 相当于 mymap["age"]=mymap["age"]+1 , 此代码正确, mymap["age"] 返回的是指针
来源: http://www.bubuko.com/infodetail-3136179.html