Golang map
// 数组、切片的问题:查找数据不方便,需要明确下标
names := []string{"张三", "李四", "王五", "马六", "钱七"}
fmt.Println(names[2]) // 王五
// So,有没有一种数据结构,能够帮我们快速的找到数据呢?
map,是一种无序的基于 key-value 的数据结构,其强大之处在于,可以使用 key( key,不允许重复 ),来快速索引数据
// 基本语法 map[KeyType]ValueType 其中,KeyType,表示键的类型;ValueType,表示键对应的值的类型 // map 类型的变量,默认初始值为nil,需要使用 make() 函数来分配内存 make(map[KeyType]ValueType, [cap]) // cap,表示 map 的容量,可选需说明的是:
- map 是引用类型,必须初始化,才能使用
- map 作为函数参数,遵循引用类型的传递机制,修改后,会对原数据产生影响
- map 是无序的,对其进行遍历时,无法决定返回的顺序,因为 map 是使用 hash 表来实现的
map 的创建和使用
(1)初始化:map,是引用类型,必须初始化后,才能使用。其初始化方式,主要有以下两种:
// 方式1:声明后,使用 make() 函数开辟内存空间 - 可以简写 // 步骤一:声明:var mapName map[键的类型]值的类型 var m1 map[string]string // 声明一个未初始化的map,可以创建一个值为 nil 的映射 fmt.Println(m1) // map[] // 即,声明后的变量,默认初始值为 nil // nil map,不能用于存储键值对,否则,会产生运行错误 //m1["name"] = "张三" // panic: assignment to entry in nil map // 步骤二:使用 make() 函数开辟内存空间,不然,就是一个 nil map // 基本语法:make(map[KeyType]ValueType, [cap]) // 其中,cap,表示map的容量,该参数虽然不是必须的,但是我们应该在初始化map时,就为其指定一个合适的容量 m1 = make(map[string]string, 10) m1["name"] = "张三" fmt.Println(m1) // map[name:张三] // 可以简写为: m2 := make(map[string]string, 10) fmt.Println(m2) m2["name"] = "张三" m2["age"] = "22" fmt.Println(m2) // map[age:22 name:张三] // 方式2:声明的时候,直接填充元素 var m3 map[string]string = map[string]string{ "name": "小明", "sex": "男", "age": "20", } fmt.Println(m3) // map[age:20 name:小明 sex:男] // 或 m4 := map[string]string{ "name": "李四", "age": "25", } fmt.Println(m4) // map[age:25 name:李四]
(2)赋值 & 判断某个 key 是否存在
- map 赋值,只能使用键值对的形式,没有 append 函数,因为 map 是无序的,不存在往中间添加数据的说法
- 基本语法:map[key] = value,如果存在 key,则会覆盖对应的 value
- 容量达到后,再给 map 填充元素,会自动扩容,并不会发生 panic,即,支持动态扩容( nil map 除外 )
func main() { colorMap := map[string]string{ "red": "红色", "blue": "蓝色", } fmt.Println(colorMap) // map[blue:蓝色 red:红色] // map 赋值 colorMap["red"] = "红色的" // 会覆盖掉之前的 fmt.Println(colorMap["red"]) // 红色的 fmt.Println(colorMap["green"]) // // So,如果不想覆盖掉之前的,或者不想查找一个根本不存在的key值 // 可以先判断一下 key 是否存在:value, ok := map[key] v, ok := colorMap["red"] // 如果存在 if ok { fmt.Println(v) // 红色的 } else { // 如果不存在 } // 或 if _, ok1 := colorMap["green"]; !ok1 { colorMap["green"] = "绿色" } fmt.Println(colorMap) // map[blue:蓝色 green:绿色 red:红色的] }
(3)遍历:遍历 map 时,元素顺序与添加键值对的顺序无关
func main() { colorMap := map[string]string{ "red": "红色", "blue": "蓝色", } fmt.Println(colorMap) // map[blue:蓝色 red:红色] // 遍历,使用 for range for k, v := range colorMap { fmt.Println(k, v) // 遍历 map 时,元素顺序与添加键值对的顺序无关 } // 只想遍历 key for k := range colorMap { fmt.Println(k) } // 只想遍历 value for _, v := range colorMap { fmt.Println(v) } }「
按指定顺序遍历 map( 略 ) 」func main() { rand.Seed(time.Now().UnixNano()) // 初始化随机数种子 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]) } }
(4)删除键值对:delete(map, key)
- map,表示要删除键值对的 map
- key,表示要删除的键值对的键
func main() { colorMap := map[string]string{ "red": "红色", "blue": "蓝色", } fmt.Println(colorMap) // map[blue:蓝色 red:红色] // 删除键值对 delete(colorMap, "red") fmt.Println(colorMap) // map[blue:蓝色] }