【一Go到底】第三十三天---map

186 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第33天,点击查看活动详情

一、map入门

1.1 map简介

map是key-value数据结构,又称为字段或者关联数组。类似其它编程语言的集合

1.2 map语法

var map变量名 map[keytype]valuetype

1.2.1 key类型

**key的类型:例如--> bool,数字,string,指针,channel,还可以是 接口,结构体,数组,通常为 int,string

slice,map,function不可以作为key类型,因为无法使用==判断

1.2.2 value类型

value类型基本和key类型一样,通常为 数字,string,map,struct

1.3 map声明例子

声明不分配内存,初始化需要make,分配内存后才可以赋值、使用

var intMap map[string]string

var intMap map[string]int

var intMap map[int]string

var intMap map[int]map[string]int

1.3.1 案例

package main

import "fmt"

func main() {
	// map声明
	var strMap map[string]string
	// map[]
	fmt.Println(strMap)

	// 先make,再使用
	// make(map[keyType]valueType, 空间大小)
	strMap = make(map[string]string, 10)
	strMap["name"] = "Amlk"
	strMap["name_2"] = "Rus"
	strMap["name_2"] = "Rsd"
	strMap["name_3"] = "Creddl"

	// key无法重复,若重复则是覆盖
	// value可以重复
	// map[name:Amlk name_2:Rsd name_3:Creddl]
	// map是无序的
	fmt.Println(strMap)
}

1.4 map注意事项

  1. map在使用前一定要make
  2. map的key不能重复,若重复,就是覆盖
  3. map的value可重复
  4. map的key-value 是无序的
  5. make初始化的长度可以省略,省略则为0

二、map的使用方式

2.1 声明再make

var intMap map[int]string
// make
intMap = make(map[int]string, 10)

2.1.1 案例

package main

import "fmt"

func main() {
	// 声明方式一

	var intMap map[int]string

	// make
	intMap = make(map[int]string, 10)

	intMap[1] = "one"
	intMap[2] = "two"
	// map[1:one 2:two]
	fmt.Println(intMap)
}

2.2 声明同时直接make

vat intMap = make(map[int]string)

2.2.1 案例

package main

import "fmt"

func main() {
	// 声明方式二

	var intMap = make(map[int]string, 10)

	intMap[1] = "one"
	intMap[2] = "two"
	// map[1:one 2:two]
	fmt.Println(intMap)
}

2.3 声明直接赋值

var intMap map[int]string = map[int]string {
    1:"one",
    .......
}

// 或者
strMap := map[string]int{
    "two":2,
    ......
}

2.3.1 案例

package main

import "fmt"

func main() {
	// 声明方式三

	var intMap map[int]string = map[int]string{
		1: "one",
		2: "two",
		3: "three",
	}
	// map[1:one 2:two 3:three]
	fmt.Println(intMap)

	// 或者
	strMap := map[string]int{
		"one":   1,
		"two":   2,
		"three": 3,
	}
	// map[one:1 three:3 two:2]
	fmt.Println(strMap)
}

三、map案例

3.1 使用map存放学生信息

使用map的key-value来存放三位学生的信息,每个学生有name和gender信息

package main

import "fmt"

func main() {
	// map存储学生信息
	// 循环实现**********************************
	stuMap := make(map[int]map[string]string, 3)

	for i := 0; i < 3; i++ {
		name := ""
		gender := ""
		fmt.Printf("请输入第%v名同学姓名:", i+1)
		fmt.Scanln(&name)
		fmt.Printf("请输入第%v名同学性别:", i+1)
		fmt.Scanln(&gender)
		stuMap[i+1] = make(map[string]string)
		stuMap[i+1]["name"] = name
		stuMap[i+1]["gender"] = gender
	}
	//请输入第1名同学姓名:wangwang
	// 请输入第1名同学性别:male
	// 请输入第2名同学姓名:Aliy
	// 请输入第2名同学性别:female
	// 请输入第3名同学姓名:Mike
	// 请输入第3名同学性别:male
	// map[1:map[gender:male name:wangwang] 2:map[gender:female name:Aliy] 3:map[gender:male name:Mike]]
	fmt.Println(stuMap)

	//直接赋值实现****************
	stu1Map := map[int]map[string]string{
		1: {"name": "WangWangDui", "gender": "male"},
		2: {"name": "Aliy", "gender": "female"},
		3: {"name": "Mike", "gender": "male"},
	}
	// map[1:map[gender:male name:WangWangDui] 2:map[gender:female name:Aliy] 3:map[gender:male name:Mike]]
	fmt.Println(stu1Map)
}

四、map的增删改查

4.1 map增加和修改

package main

import "fmt"

func main() {
	// 增加和更新

	strMap := make(map[string]string)

	// 增加
	strMap["one"] = "111"
	strMap["two"] = "222"
	strMap["three"] = "333"

	// 修改,因为key不能重复,那么重新赋值就是更新
	strMap["three"] = "Three"
	// map[one:111 three:Three two:222]
	fmt.Println(strMap)
}

4.2 map删除

4.2.1 语法

delete(map,"key' ),delete是一个内置函数,如果key存在, 就删除该key-value,如果key不存在,不操作,但是也不会报错

delete(mapName, "KEY")

注意事项

  1. map无法一次性删除所有的key,只能循环遍历,逐个删除
  2. 或者 map = make(...),make一个新的,让原来的成为垃圾,被gc回收

4.2.1 案例

package main

import "fmt"

func main() {
	// 增加和更新

	strMap := make(map[string]string)

	// 增加
	strMap["one"] = "111"
	strMap["two"] = "222"
	strMap["three"] = "333"

	// 修改,因为key不能重复,那么重新赋值就是更新
	strMap["three"] = "Three"
	// map[one:111 three:Three two:222]
	fmt.Println(strMap)

	// 删除
	delete(strMap, "two")
	// map[one:111 three:Three]
	fmt.Println(strMap)

	// 删除不存在的键是否报错
	delete(strMap, "1111")
	// map[one:111 three:Three]
	fmt.Println(strMap)

	// make清空
	strMap = make(map[string]string)
	// map[]
	fmt.Println(strMap)
}

4.3 查询

package main

import "fmt"

func main() {
	findMap := make(map[string]string)
	findMap["One"] = "1111"
	findMap["Two"] = "2222"
	findMap["Three"] = "3333"

	value, result := findMap["One"]
	if result {
		// 存在,值 = 1111
		fmt.Printf("存在,值 = %v\n", value)
	} else {
		fmt.Printf("%v不存在\n", findMap["One"])
	}
}

五、map的长度及遍历

map遍历使用for-range结构遍历

5.1 map的长度

map的长度就是map中存在几个key-value对

package main

import "fmt"

func main() {
	// map遍历

	strMap := make(map[string]string)

	strMap["one"] = "1111"
	strMap["two"] = "2222"
	strMap["three"] = "3333"
	// 查看
	fmt.Println(strMap)
	// 查看长度
	// strMap的长度 = 3
	fmt.Printf("strMap的长度 = %v\n", len(strMap))

5.2 单层map循环

package main

import "fmt"

func main() {
	// map遍历

	strMap := make(map[string]string)

	strMap["one"] = "1111"
	strMap["two"] = "2222"
	strMap["three"] = "3333"
	// 查看
	fmt.Println(strMap)

	// for-range
	for k, v := range strMap {
		//key = one, value = 1111
		// key = two, value = 2222
		// key = three, value = 3333
		fmt.Printf("key = %v, value = %v\n", k, v)
	}
}

5.3 多层map循环

package main

import "fmt"

func main() {

	strMap1 := make(map[string]map[string]string)

	strMap1["One"] = make(map[string]string, 3)
	strMap1["One"]["one"] = "1"
	strMap1["One"]["two"] = "2"
	strMap1["One"]["three"] = "3"

	strMap1["Two"] = make(map[string]string, 3)
	strMap1["Two"]["one"] = "1"
	strMap1["Two"]["two"] = "2"
	strMap1["Two"]["Three"] = "3"

	strMap1["Three"] = make(map[string]string, 3)
	strMap1["Three"]["one"] = "1"
	strMap1["Three"]["two"] = "2"
	strMap1["Three"]["three"] = "3"

	for k1, v1 := range strMap1 {
		fmt.Printf("外层key = %v, value = %v\n", k1, v1)
		for k2, v2 := range v1 {
			fmt.Printf("\t内层key = %v, value = %v\n", k2, v2)
		}
		// 外层key = Three, value = map[one:1 three:3 two:2]
		// 		内层key = one, value = 1
		// 		内层key = two, value = 2
		// 		内层key = three, value = 3
		// 外层key = One, value = map[one:1 three:3 two:2]
		// 		内层key = one, value = 1
		// 		内层key = two, value = 2
		// 		内层key = three, value = 3
		// 外层key = Two, value = map[Three:3 one:1 two:2]
		// 		内层key = Three, value = 3
		// 		内层key = one, value = 1
		// 		内层key = two, value = 2
	}
}


六、map切片

切片的数据类型如果是map,则我们称为slice of map, map切片,这样使用则map个数就可以动态变化了。

6.1 案例演示

要求:使用一个map来记录monster的信息name和age,也就是说一个monster对应一个map,并且妖怪的个数可以动态的增加=>map切片

package main

import "fmt"

func main() {
	// map切片使用

	// 声明一个map切片,make长度为2
	monsters := make([]map[string]string, 2)
	// 增加第一个元素
	if monsters[0] == nil {
		monsters[0] = make(map[string]string, 2)
		monsters[0]["name"] = "牛牛"
		monsters[0]["age"] = "1999"
	}

	if monsters[1] == nil {
		monsters[1] = make(map[string]string, 2)
		monsters[1]["name"] = "牛马"
		monsters[1]["age"] = "100"
	}

	// 新增
	newMonster := map[string]string{
		"name": "猪道",
		"age":  "40",
	}

	// 使用append添加元素到monster中
	monsters = append(monsters, newMonster)

	// [map[age:1999 name:牛牛] map[age:100 name:牛马] map[age:40 name:猪道]]
	fmt.Println(monsters)

}

七、map排序

  1. golang中没有-一个专门的方法针对map的key进行排序
  2. golang中的map默认是无序的,注意也不是按照添加的顺序存放的,你每次遍历,得到的输出可能不一样,请看本章[案例演示]
  3. golang中map的排序,是先将key进行排序,然后根据key值遍历输出即可

7.1 案例演示

package main

import (
	"fmt"
	"sort"
)

func main() {
	// map排序案例

	intMap := make(map[int]int, 10)

	intMap[0] = 10010
	intMap[9] = 1330
	intMap[5] = 2220
	intMap[8] = 8100

	// map[0:10010 2:2220 3:1330 8:8100]
	fmt.Println(intMap)

	// 按照key的顺序排序
	keys := []int{}

	for k, _ := range intMap {
		keys = append(keys, k)
	}
	// 调用sort.Intskeys()方法
	sort.Ints(keys)
	fmt.Printf("排序后= %v\n", keys)

	// 用key取map中的值
	// index,value 会取出。这里只取keys中的value,也就是刚刚添加进群的key
	for _, k := range keys {
		// map[0] = 10010
		// map[5] = 2220
		// map[8] = 8100
		// map[9] = 1330
		fmt.Printf("map[%v] = %v\n", k, intMap[k])
	}
}

八、map使用细节

  1. map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map。详见8.1 案例一
  2. map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态的增长键值对(key-value) 详见8.2 案例二
  3. map的value也经常使用struct类型,更适合管理复杂的数据(比前面value是-一个map更好),比如value为Student结构体。详见8.3 案例三

8.1 案例一

package main

import "fmt"

func modify(intMap map[int]int) {
	intMap[1] = 1111
}

func main() {
	// map引用类型
	intMap := map[int]int{
		1: 1001,
		2: 1002,
		3: 1003,
	}

	modify(intMap)
	// after modify() = map[1:1111 2:1002 3:1003]
	fmt.Printf("after modify() = %v\n", intMap)

}

8.2 案例二

package main

import "fmt"

func main() {
	// 定义map
	// make长度为2
	intMap := make(map[int]int, 2)
	// 添加4个数据
	intMap[0] = 1000
	intMap[1] = 1000
	intMap[2] = 1000
	intMap[5] = 1000

	// intMap =  map[0:1000 1:1000 2:1000 5:1000]
	fmt.Println("intMap = ", intMap)

}

8.3 案例三

package main

import "fmt"

// 定义一个Stu结构体
type Stu struct {
	Name   string
	Age    int
	Native string
}

func main() {
	// 结构体案例

	/*
		1. map的key为学生的学好,全局唯一
		2. map的value为学生的结构体,包含学生的名字,籍贯
	*/

	// 声明map

	students := make(map[string]Stu, 5)

	// 或者不写结构体中key ===》 stu1 := Stu{"Aliy",20,"USA"}

	stu1 := Stu{Name: "Aliy", Age: 20, Native: "USA"}
	stu2 := Stu{Name: "Bob", Age: 21, Native: "UK"}
	stu3 := Stu{Name: "Crely", Age: 18, Native: "France"}

	students["stu1"] = stu1
	students["stu2"] = stu2
	students["stu3"] = stu3

	// 学生信息 = map[stu1:{Aliy 20 USA} stu2:{Bob 21 UK} stu3:{Crely 18 France}]
	fmt.Printf("学生信息 = %v\n", students)
	fmt.Println()

	// 遍历学生信息

	for k, v := range students {
		fmt.Printf("学生编号%v的信息是:\n", k)
		fmt.Printf("\t姓名 = %v, 年龄 = %v, 籍贯 = %v\n", v.Name, v.Age, v.Native)
		//
		// 学生编号stu1的信息是:
		// 姓名 = Aliy, 年龄 = 20, 籍贯 = USA
		// 学生编号stu2的信息是:
		// 姓名 = Bob, 年龄 = 21, 籍贯 = UK
		// 学生编号stu3的信息是:
		// 姓名 = Crely, 年龄 = 18, 籍贯 = France
	}

}

九、map案例实践

  1. 使用map[string]map[string]sting 的map类型
  2. key:表示用户名,是唯一- -的,不可以重复
  3. 如果某个用户名存在,就将其密码修改"888888", 如果不存在就增加这个用户信息,(包括昵称nickname和密码pwd) 4 .编写一个函数modifyUser(users map[string]map[string]sting, name string) 完成上述功能
package main

import "fmt"

// 定义modifyUser函数
func modifyUser(users map[string]map[string]string, name string) {
	if users[name] != nil {
		users[name]["pwd"] = "88888888"
	} else {
		users[name] = make(map[string]string)
		users[name]["pwd"] = "88888888"
		users[name]["nickname"] = "nickname---" + name
	}
}

func main() {
	// 声明map

	infoMap := make(map[string]map[string]string)
	infoMap["Aliy"] = make(map[string]string)
	infoMap["Aliy"]["nickname"] = "nickname---Aliy"
	infoMap["Aliy"]["pwd"] = "123456789"

	infoMap["Bob"] = make(map[string]string)
	infoMap["Bob"]["nickname"] = "nickname---bob"
	infoMap["Bob"]["pwd"] = "456123465123"

	modifyUser(infoMap, "Aliy")
	modifyUser(infoMap, "aliy")

	for k, v := range infoMap {
		fmt.Printf("%v的信息是: \n", k)
		for k1, v1 := range v {
			fmt.Printf("\t %v = %v\n", k1, v1)
		}
	}
	// Aliy的信息是:
	// 	pwd = 88888888
	// 	nickname = nickname---Aliy
	// Bob的信息是:
	// 	nickname = nickname---bob
	// 	pwd = 456123465123
	// aliy的信息是:
	// 	pwd = 88888888
	// 	nickname = nickname---aliy

}