笔上得来终觉浅,绝知此事要躬行
🔥 个人主页:星云爱编程
🔥 所属专栏:Golang
🌷追光的人,终会万丈光芒
🎉欢迎大家点赞👍评论📝收藏⭐文章
![]()
1基本介绍
Go语言中的 map 是一种无序的键值对集合,类似于其他语言中的字典或哈希表。它通过键(key)来快速查找对应的值(value),键必须是唯一的,而值可以重复。
2.map的基本特性
- 键值对存储 :存储的数据是键值对形式, key: value
- 无序性 :遍历map时,顺序是不固定的
- 动态大小 :map的大小可以动态增长
- 引用类型 :map是引用类型,传递时传递的是引用
3.map的声明
基本语法:
var map变量名 map[keyType]ValueType
说明:
1.key可以是什么类型?
key可以为多种类型:整数型,浮点型,bool型,string,指针,channel,还可以是只包含前面几种类型的接口,结构体,数组;key一般为int,string
注意:slice,map和function不能用作key的类型,因为它们无法用==来判断
2.value可以是什么类型
value的类型和key的类型基本一样,通常为数字(整数、浮点数),string,map,struct
3.声明举例
var a map[int]string
var b map[string]string
var c map[string]int
注意:声明是不会分配内存的,初始化需要make分配内存后才能赋值和使用
如下诉代码将会报错:
var m map[string]int
m["jack"]=10
fmt.Println(m)
说明:
- map在使用前一定要make
- map的key是不能重复的,如果重复了,则以覆盖的形式更换对应的value
- map的value是可以相同的
- map的key-value是无序的
4.map的使用
第一种方式:
var a map[string]string
a=make(map[string]string,10)
a["name"]="jack"
a["age"]="111"
第二种方式:
stu:=make(map[string]string)
stu["stu1"]="jack"
stu["stu2"]="tom"
第三种方式:
var stu map[string]string=map[string]string{
"stu1":"jack",
"stu2":"tom",
}
stu :=map[string]string{
"stu1":"jack",
"stu2":"tom",
}
5.map的增删查改操作
1.map增加和更新
map["key"]=value
说明:如果key不存在,就是增加,如果key存在即是修改
2.map删除
delete(map,"key")
说明:
- delete是一个内置函数,如果key存在,就删除该key-value;若key不存在,则不进行操作,也不会报错
- 如果我们要删除map的所有值,没有一个专门的方法一次删除,可以遍历map,逐个删除;或者map=make(...),make一个新的,让原来的成为垃圾,被gc回收
3.map查找
value, exists := m[key]
说明:如果m[key]存在,则exists为true,反之为false
4.案例
package main
import "fmt"
func main() {
// 创建一个 map
m := make(map[string]int)
// 1. 增加元素
m["apple"] = 1
m["banana"] = 2
fmt.Println("增加元素后:", m)
// 2. 查找元素
value, exists := m["apple"]
if exists {
fmt.Println("查找元素: apple ->", value)
} else {
fmt.Println("未找到元素: apple")
}
// 3. 修改元素
m["banana"] = 3
fmt.Println("修改元素后:", m)
// 4. 删除元素
delete(m, "banana")
fmt.Println("删除元素后:", m)
}
6.map的遍历
在 Go 语言中, map 的遍历操作可以通过 for- range 实现。
案例:
package main
import "fmt"
func main() {
// 创建一个 map
m := map[string]int{
"apple": 1,
"banana": 2,
"cherry": 3,
}
// 遍历 map
for key, value := range m {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
}
说明:
- for range 语法 : for key, value := range m 用于遍历 map , key 是键, value 是值。
- map 的遍历顺序是随机的,因为 map 是无序的。
- 如果只需要键或值,可以使用 _ 忽略不需要的部分。
7.map的长度
在 Go 语言中, map 的长度可以通过内置函数 len 来获取。
案例:
package main
import "fmt"
func main() {
// 创建一个 map
m := map[string]int{
"apple": 1,
"banana": 2,
"cherry": 3,
}
// 获取 map 的长度
length := len(m)
fmt.Println("map 的长度:", length)
}
说明:
- len 函数 : len(m) 返回 map 中键值对的数量。
- 空 map :如果 map 为空, len(m) 返回 0 。
- nil map :如果 map 是 nil , len(m) 也返回 0 。
- 并发安全 : len 函数在并发环境下是安全的,但如果在遍历或修改 map 的同时调用 len ,可能会导致数据竞争,需要使用同步机制(如 sync.Mutex )来保护。
- 性能 : len 函数的时间复杂度是 O(1),因为它只是返回 map 的内部计数器。
例如:
package main
import "fmt"
func main() {
// 创建一个空 map
m := make(map[string]int)
fmt.Println("空 map 的长度:", len(m)) // 输出: 0
// 添加元素
m["apple"] = 1
m["banana"] = 2
fmt.Println("添加元素后 map 的长度:", len(m)) // 输出: 2
// 删除元素
delete(m, "apple")
fmt.Println("删除元素后 map 的长度:", len(m)) // 输出: 1
// nil map
var nilMap map[string]int
fmt.Println("nil map 的长度:", len(nilMap)) // 输出: 0
}
8.map切片
在 Go 语言中, map 切片是指一个切片,其中每个元素都是一个 map 。这种数据结构常用于需要存储多个 map 的场景。
使用案例:
package main
import "fmt"
func main() {
// 定义一个 map 切片
var mapSlice []map[string]int
// 初始化 map 切片
mapSlice = make([]map[string]int, 3) // 创建一个长度为 3 的切片
for i := range mapSlice {
mapSlice[i] = make(map[string]int) // 初始化每个 map
}
// 添加元素
mapSlice[0]["apple"] = 1
mapSlice[1]["banana"] = 2
mapSlice[2]["cherry"] = 3
// 遍历 map 切片
for i, m := range mapSlice {
fmt.Printf("mapSlice[%d]: %v\n", i, m)
}
}
package main
import "fmt"
func main(){
var Stu []map[string]string
Stu=make([]map[string]string,2)
//增加学生信息
if Stu[0]==nil{
Stu[0]=make(map[string]string,2)
Stu[0]["name"]="欣欣"
Stu[0]["age"]="19"
}
if Stu[1]==nil{
Stu[1]=make(map[string]string,2)
Stu[1]["name"]="依依"
Stu[1]["age"]="18"
}
fmt.Println(Stu)
}
说明:
- 定义 map 切片 : var mapSlice []map[string]int 定义了一个 map 切片,其中每个元素都是一个 map[string]int 。
- 初始化 map 切片 :使用 make([]map[string]int, 3) 创建一个长度为 3 的切片,然后遍历切片,为每个元素初始化一个 map 。
- 添加元素 :通过 mapSlice[i][key] = value 向每个 map 中添加键值对。
- 遍历 map 切片 :使用 for range 遍历 map 切片,并输出每个 map 的内容。
注意事项:
- 初始化 : map 切片中的每个 map 需要单独初始化,否则会引发运行时错误( nil map )。
- 动态扩展 : map 切片可以动态扩展,使用 append 添加新的 map 。
- 并发安全 :如果多个 goroutine 同时操作 map 切片,需要使用同步机制(如 sync.Mutex )来保护。
动态扩展:
package main
import "fmt"
func main() {
// 定义一个 map 切片
var mapSlice []map[string]int
// 动态添加 map
newMap := map[string]int{"orange": 4}
mapSlice = append(mapSlice, newMap)
// 遍历 map 切片
for i, m := range mapSlice {
fmt.Printf("mapSlice[%d]: %v\n", i, m)
}
}
9.map排序
介绍:
(1)Go 中没有专门的方法对map的key进行排序;
(2)Go 中的map默认是无序的,每次遍历输出的顺序是随机的;
(3)Go 中map的排序,是先将key进行排序,然后根据key值遍历输出。
案例:对键排序
package main
import (
"fmt"
"sort"
)
func main() {
m := map[string]int{
"apple": 3,
"banana": 1,
"cherry": 2,
}
// 获取所有键
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
// 对键排序
sort.Strings(keys)
// 按排序后的键输出
for _, k := range keys {
fmt.Printf("%s: %d\n", k, m[k])
}
}
说明:
- 提取 map 的所有键到切片中。
- 使用 sort.Strings 对键排序。
- 按排序后的键输出对应的值。
案例2:对值排序
package main
import (
"fmt"
"sort"
)
func main() {
m := map[string]int{
"apple": 3,
"banana": 1,
"cherry": 2,
}
// 定义一个结构体用于存储键值对
type kv struct {
Key string
Value int
}
// 将 map 转换为切片
var kvs []kv
for k, v := range m {
kvs = append(kvs, kv{k, v})
}
// 对值排序
sort.Slice(kvs, func(i, j int) bool {
return kvs[i].Value < kvs[j].Value
})
// 按排序后的值输出
for _, kv := range kvs {
fmt.Printf("%s: %d\n", kv.Key, kv.Value)
}
}
说明:
- 定义一个结构体 kv 存储键值对。
- 将 map 转换为 kv 切片。
- 使用 sort.Slice 对值排序。
- 按排序后的值输出对应的键。
10.map的使用细节
(1)map是引用类型,遵守引用类型传递的机制,在一个函数接受map并修改后,会直接修改原来的map;
例子:
package main
import "fmt"
// 修改 map 的函数
func modifyMap(m map[string]int) {
m["apple"] = 10
m["banana"] = 20
}
func main() {
// 创建一个 map
m := map[string]int{
"apple": 1,
"banana": 2,
}
fmt.Println("修改前:", m)
modifyMap(m)
fmt.Println("修改后:", m)
}
(2)map的容量满后,继续往map中添加元素,map会自动扩容,并不会发生panic,也就是说map能动态地增长键值对;
案例:
package main
import "fmt"
func main() {
// 创建一个初始容量较小的 map
m := make(map[int]int, 2)
// 添加元素,观察 map 的动态扩容
for i := 0; i < 10; i++ {
m[i] = i * 10
fmt.Printf("添加元素: %d -> %d, map 长度: %d\n", i, m[i], len(m))
}
}
(3)map的value经常使用struct类型,更适合管理复杂的数据。
结语
感谢您的耐心阅读,希望这篇博客能够为您带来新的视角和启发。如果您觉得内容有价值,不妨动动手指,给个赞👍,让更多的朋友看到。同时,点击关注🔔,不错过我们的每一次精彩分享。若想随时回顾这些知识点,别忘了收藏⭐,让知识触手可及。您的支持是我们前进的动力,期待与您在下一次分享中相遇!
路漫漫其修远兮,吾将上下而求索。