1、前言
- 计算机科学里面最有用的数据结构之一就是hash表。不同的hash表实现提供了很多独特的特性。但是基本上都包括元素查询,添加和删除。Go提供了一个内置的类型map,这个类型实现了hash表的基本功能。
- 所以在 Go 语言里要使用 hash 表,那么就用 map 吧。
2、map 的基本使用
2.1、声明和初始化
2.1.1、声明
var m map[string]int //此时 m 还没有被分配内存空间,是个 nil
- 如果没有给 map 分配空间,之间向其中插入数据,就会无情报错。
var m map[string]int
m["中国"] = 1
//报错:panic: assignment to entry in nil map
注意!在声明 map 的时候,key 的数据类型有要求,必须是可比较的类型,而对于 value,则可以是任意数据类型。可比较类型比较多,记住比较麻烦,但是不可比较类型只有三个:slice、map、func。
2.1.2、初始化
- 对 map 进行初始化,其实就是给 map 分配空间。接下来介绍三种初始化 map 的方式。
- 方式一
var m = map[string]int{
} //不要笑看了这一对大括号,这样就算给 map 分配空间了
m["中国"] = 1
- 方式二
var m map[string]int
m = make(map[string]int, 2)
- 方式三
var m = map[string]int{
"中国" : 1,
"美国" : 2,
}
2.2、增删改查
var m = map[string]int{
}
//1.增
m["中国"] = 1
m["美国"] = 2 //m->map[中国:1 美国:2]
//2.删
delete(m, "美国") //m->map[中国:1]
//3.改
m["中国"] = 100 //m->map[中国:0]
//4.查
val, ok := m["中国"] //val=100, ok=true
- 其中还可以这样查,就是不用 ok 去接收某个键值对在不在。
val := m["中国"] //val=100
- 上面在删除 map 中某个键值对的时候,如果 map 中不存在对应的 key,则不作任何改变;在查询 map 中存不存在某个键值对的时候,如果不存在,则会返回 value 的数据类型的零值,例如此处 value 的数据类型是 int,int 的零值是 0。
2.3、遍历 map
func Traverse() {
m := map[string]int{
"china" : 1,
"america" : 2,
"england" : 3,
"japan" : 4,
"russia" : 5,
"germany" : 6,
"india" : 7,
}
for k, v := range m {
fmt.Printf("number %d is %s\n", v, k)
}
}
number 5 is russia
number 6 is germany
number 7 is india
number 1 is china
number 2 is america
number 3 is england
number 4 is japan
- 看到遍历结果显示的顺序与自己插入数据的顺序不符,但是我就是想有序遍历该怎么办呢?
func SortTraverse() {
m := map[string]int{
"china" : 1,
"america" : 2,
"england" : 3,
"japan" : 4,
"russia" : 5,
"germany" : 6,
"india" : 7,
}
keys := []string{
}
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("number %d is %s\n", m[k], k)
}
}
number 2 is america
number 1 is china
number 3 is england
number 6 is germany
number 7 is india
number 4 is japan
number 5 is russia
2.4、函数传参
- map 作为函数参数,传递的其实是 map 的地址值,不信我们来看看。
func ChangeMap(m map[string]int) {
fmt.Printf("对 m 未做修改前:m 的地址是 %p\n", m)
m["美国"] = 2
fmt.Printf("对 m 插入1条数据后:m 的地址是 %p\n", m)
m["俄罗斯"] = 3
fmt.Printf("对 m 插入2条数据后:m 的地址是 %p\n", m)
for i := 0; i < 9999998; i++ {
m["国家" + strconv.Itoa(i)] = i
}
fmt.Printf("对 m 插入10000000条数据后:m 的地址是 %p\n", m)
}
func main() {
m := make(map[string]int, 2)
m["中国"] = 1
//m["美国"] = 2
fmt.Printf("main.传参前,m 的地址是 %p\n", m)
Map.ChangeMap(m)
fmt.Println(m["国家123456"])
}
main.传参前,m 的地址是 0xc0000b6330
ChangeMap.对 m 未做修改前:m 的地址是 0xc0000b6330
ChangeMap.对 m 插入1条数据后:m 的地址是 0xc0000b6330
ChangeMap.对 m 插入2条数据后:m 的地址是 0xc0000b6330
ChangeMap.对 m 插入10000000条数据后:m 的地址是 0xc0000b6330
main. 123456