package main
import (
"fmt"
"sort"
"sync"
)
/*
map是一种特殊的数据结构 一种元素对(pair)的无序集合,pair对应一个key(索引)和你一个value(值)
所以这个结构也称为关联数组或字典,可以通过key找value,像python中的字典
*/
//map是引用类型
// map 是可以动态增长的,未初始化的 map 的值是 nil,使用函数 len() 可以获取 map 中 pair 的数目。
//声明格式:var map变量名 map[键类型] 键对应的值类型
//var mapname map[keytype] vauletype
func main() {
//声明并初始化一个map
mapdict:=map[string]int{"hello":1,"world":2}
fmt.Println(mapdict) //map[hello:1 world:2]
fmt.Println(mapdict["hello"]) //1
//引用mapdict
mapdict1:=mapdict
//修改mapdict1
mapdict1["kk"]=3
fmt.Println(mapdict1) //map[hello:1 kk:3 world:2]
//mapdict1是mapdict的引用,对mapdict1修也会影响到mapdict
fmt.Println(mapdict) //map[hello:1 kk:3 world:2]
makemap()
dicts()
Formap()
sortFormap()
mapdelete()
gofunc()
syncMap()
}
//map容量
func makemap() {
//和数组不同,map可以根据新增的key-value动态伸缩,因此不存在最大限制,但可以标明map的初始容量
//make构造一个map
map1:=make(map[string]int,100)
fmt.Println(len(map1)) //0
//可以使用 make(),但不能使用 new() 来构造 map,如果错误的使用 new() 分配了一个引用对象,
//会获得一个空引用的指针,相当于声明了一个未初始化的变量并且取了它的地址
//mapcreated:=new(map[string]string)
//mapcreated["key"]="value" //报错: mapcreated["key"] (type *map[string]string does not support indexing)
//fmt.Println(mapcreated)
}
//用切片作为map的值,即实现像key对应多个value
func dicts() {
map1:=make(map[string] []int)
map2:=make(map[string] *[]int)
map1["num"]=[]int{10,20,30,40}
map2["内存地址"]=&[]int{0,1,2,3}
fmt.Println(map1) //map[num:[10 20 30 40]]
fmt.Println(map2) //map[内存地址:0xc00000c0e0]
}
//遍历map
func Formap() {
map1:=make(map[string] int)
map1["index"]=0
map1["value"]=10
map1["caina"]=996
//可以将不需要的键使用_改为匿名变量形式。
for k,v :=range map1{
fmt.Println(k,v)
/*
遍历输出元素的顺序与填充顺序无关,不能期望 map 在遍历时返回某种期望顺序的结果。
index 0
value 10
caina 996
*/
}
}
//特定顺序的遍历
func sortFormap() {
map1:=make(map[string]int)
map1["a"]=200
map1["b"]=20
map1["c"]=1
//声明一个切片保存map数据
//key:=[]string{}
slice:=[]int{}
//将map值的数据遍历添加到切片中
for _,v:=range map1{
slice=append(slice,v)
}
fmt.Println(slice) //[200 20 1]
//sort.Strings(key)
sort.Ints(slice) //[1 20 200]
fmt.Println(slice)
}
//删除map中的键值对
func mapdelete() {
map1:=make(map[string]int)
map1["a"]=200
map1["b"]=20
map1["c"]=1
//通过key值删除键值对
delete(map1,"a")
fmt.Println(map1)//map[b:20 c:1]
}
//Go语言中并没有为 map 提供任何清空所有元素的函数、方法,清空 map 的唯一办法就是重新 make 一个新的 map,
// 不用担心垃圾回收的效率,Go语言中的并行垃圾回收效率比写一个清空函数要高效的多
//并发环境中使用的map
//Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的。
func gofunc() {
//创建一个int到int的映射
m:=make(map[int]int)
//开启一段并发代码
go func() {
//循环对map进行写入
for {
m[1]=1
}
}()
//开启一段并发代码
go func() {
//循环对map读取
for{
_=m[1]
}
}()
//无限循环,让并发程序在后台执行
for{
fmt.Println()
}
}
//fatal error: concurrent map read and map write
//并发的 map 读和 map 写,也就是说使用了两个并发函数不断地对 map 进行读和写而发生了竞态问题,map 内部会对这种并发操作进行检查并提前发现。
//需要并发读写时,一般的做法是加锁,但这样性能并不高
//Go语言在 1.9 版本中提供了一种效率较高的并发安全的 sync.Map
/*
sync.Map 有以下特性:
无须初始化,直接声明即可。
sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。
使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。
map与sync.Map的应用场景:
sync.Map 没有提供获取 map 数量的方法,替代方法是在获取 sync.Map 时遍历自行计算数量,sync.Map 为了保证并发安全有一些性能损失,
因此在非并发情况下,使用 map 相比使用 sync.Map 会有更好的性能。
*/
func syncMap() {
//声明scene,类型为sync.Map,不能用make创建
var scene sync.Map
//将键值对保存到sync.Map
//sync.Map 将键和值以 interface{} 类型进行保存。
scene.Store("scene1","value1")
scene.Store("scene2",2)
scene.Store("scene3",10)
//从sync.Map中根据键取值
fmt.Println(scene.Load("scene1")) //value1 true
//根据键删除值
scene.Delete("scene2")
//遍历所有sync.Map中的键值对
//Range() 方法可以遍历 sync.Map,遍历需要提供一个匿名函数,参数为 k、v,类型为 interface{},
// 每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。
scene.Range(func(key, value interface{}) bool {
fmt.Println("iterate:",key,value)
/*
iterate: scene1 value1
iterate: scene3 10
*/
return true
})
}
Go中的map详解
最新推荐文章于 2024-05-12 12:18:53 发布