1.1.1. 一、map 的基本介绍。
map 是 key-value 数据结构,又称为字段或者关联数组。**类似其它编程语言的集合**, 在编程中是经常使用到。
1.1.2. 二、map 的声明语法。
1、语法如下:
var map 变量名 map[keytype]valuetype
// 示例: var students map[string]string
- keytype 是键的类型:可以是 bool、 数字、string、指针、channel、 还可以是只包含前面几个类型的接口、 结构体、数组。通常 key 为 int 、string。注意:slice, map 还有 function 不可以,因为这几个没法用 == 来判断。
- valuetype 是值的类型:可以的类型 和 keytype 基本一样。通常为: 数字(整数、浮点数)、string、map、struct。
- 如果key重复了,后面设置的值会覆盖前面的值。
2、map 声明的举例。
var a map[string]string
键类型是string,值类型是string。var a map[string]int
键类型是string,值类型是int。var a map[string]map[string]string
键类型是string,值类型是map[string]string ,另一个map。
注意:声明是不会分配内存的,make 分配内存后才能赋值和使用。
3、给map分配内存。
var students map[string]string
// 使用map前,需要先给map分配空间
students = make(map[string]string,10)
students["s1"] = "张三"
students["s2"] = "李四"
fmt.Println(students) // map[s1:张三 s2:李四]
// 声明时直接make分配空间,不写空间大小
var students = make(map[string]string)
students["s1"] = "张三"
students["s2"] = "李四"
fmt.Println(students) // map[s1:张三 s2:李四]
students := map[string]string{
"s1" : "张三",
"s2" : "李四",
}
students["s3"] = "王5"
fmt.Println(students) // map[s1:张三 s2:李四 s3:王5]
4、示例嵌套map的使用。
var students = make(map[string]map[string]string)
//第一个学生
students["001"] = make(map[string]string)
//设置students["001"]是一个map。这里设置这个map的“name”
students["001"]["name"] = "张三"
students["001"]["sex"] = "男"
students["001"]["age"] = "18"
// map[001:map[age:18 name:张三 sex:男]]
fmt.Println(students)
1.1.3. 三、map的CRUD(增删改查)操作。
1、增加、修改操作。
map["key"] = value //如果 key 还没有,就是增加,如果 key 存在就是修改。
2、删除 map 的元素:
delete(map,"key") // 删除map 中键为"key"的元素
delete 是一个内置函数,如果 key 存在,就删除该 key-value,如果 key 不存在, 不操作,但是也不会报错。
var students = make(map[string]string)
students["name"] = "张三"
students["age"] = "18"
// map[age:18 name:张三]
fmt.Println(students)
delete(students,"name") //删除key是"name"的元素
delete(students,"sss") //删除不存在的key,不报错。
fmt.Println(students) //map[age:18]
如果我们要删除 map 的所有 key ,没有一个专门的方法一次删除,可以遍历一下 key,逐个删除或者 map = make(...),make 一个新的,让原来的成为垃圾,被 gc 回收。
3、查找map的元素。
value,flag := students["name"]
说明:查找返回两个值。第一个是根据key找到的值,第二个是bool型表示是否找到。
- 如果找到了,flag等于true。
- 如果找不到 value 会返回值类型的零值,flag等于false。
- 也可以使用
students["name"] != nil
判断存在这个key。
示例如下:
var students = make(map[string]string)
students["name"] = "张三"
students["age"] = "18"
// map的查找
value,flag := students["name"]
if flag {
// 查找到了value=张三,flag=true
fmt.Printf("查找到了value=%v,flag=%v",value,flag)
}else {
// 如果找不到 value 会返回值类型的零值,flag=false
fmt.Printf("不存在value=%v,flag=%v",value,flag)
}
1.1.4. 四、map的遍历。
map不能用普通for循环变量,只能使用for-range遍历。示例如下:
var students = make(map[string]string)
students["name"] = "张三"
students["age"] = "18"
//遍历,k就是键的值。v就是值。
for k,v := range students {
fmt.Printf("键是 %v,值是 %v \n",k,v)
}
1.1.5. 五、map的长度。
使用len()函数。可以得到map的长度,也就是有多少个键值对。
var students = make(map[string]string)
students["name"] = "张三"
students["age"] = "18"
fmt.Println(len(students)) // 2
1.1.6. 六、map的切片。
切片的数据类型如果是 map,则我们称为 slice of map,map切片,这样使用则 map 的个数就可以动态变化了。
实际上就是一个数组,里面的每一个元素都是一个map。
var students = make([]map[string]string)
完整示例如下:
// 声明 map[string]string 类型的切片,并且数组大小是2
var students = make([]map[string]string,2)
//设置第一个元素
if students[0] == nil {
students[0] = make(map[string]string)
students[0]["name"] = "张三"
students[0]["age"] = "18"
}
if students[1] == nil {
students[1] = make(map[string]string)
students[1]["name"] = "张三"
students[1]["age"] = "18"
}
// 没有students[2],这里会报错:数组越界。因为上面只声明了2个空间。如果需要加元素,使用append。
// [map[age:18 name:张三] map[age:18 name:张三]]
fmt.Println(students)
stu := map[string]string{
"name":"王5",
}
// 给切片增加一个元素。
students = append(students, stu)
// [map[age:18 name:张三] map[age:18 name:张三] map[name:王5]]
fmt.Println(students)
注意几点:
- var students = make([]map[string]string,2) 这个表示切片的初始大小是2。对
map[string]string
类型切片。 - 其实就是声明了一个数组,里面的每一个元素都是一个map。
- 不能使用 students[2] ,使用了会报错:数组越界。因为上面只声明了2个空间。如果需要加元素,使用append。
- students = append(students, stu) 给切片(动态数组)增加了一个元素。
1.1.7. 七、对map的key排序。
map是无序的,如果想按照key对map排序输出。实现代码如下:
// 声明 map
var studentsMp = make(map[int]int,6)
studentsMp[6] = 10
studentsMp[81] = 9
studentsMp[34] = 67
studentsMp[8] = 4
// int 类型切片
var keys []int
for k,_ := range studentsMp{
keys = append(keys,k)
}
// 把keys递增排序
sort.Ints(keys)
for _,k := range keys{
fmt.Println(k,studentsMp[k]) //按照key获取studentsMp的值
}
整体思路是把key放在一个切片里。然后对key的切片排序,使用的是sort包的sort.Ints()
方法。
1.1.8. 八、map的使用陷阱。
- map 是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改外部原来的 map 。
- map 的容量达到后,再想 map 增加元素,会自动扩容,并不会发生 panic,也就是说 map 能动态的增长 键值对(key-value)。