{ m:=make(map[string]int)//创建一个字典 m["a"]=1 m["b"]=2 m2:=map[int]struct{//匿名结构体 xint }{ 1:{x:100},2:{x:200},} fmt.Println(m,m2) }@H_403_0@
@H_403_0@字典的基本操作 @H_403_0@比如:
{ m:=make(map[string]int) m["route"]=66//添加key i:=m["route"]//读取key j:=m["root"]//thevaluetypeisint,sothezerovalueis0 n:=len(m)//获取长度 //n:=cap(m)//???引发一个思考 delete(m,"route")//删除key }@H_403_0@如果访问不存在的键,不会引发错误,而会默认返回ValueType的零值,那么还能否根据零值来判断key的存在呢? @H_403_0@在读取map操作时,可以使用双返回值来正常读取map,比如:
{ j,ok:=m["root"] } 说明: ok是个bool类型变量,如果key真实存在,则ok的值为true,反之为false,如果你只是想测试key是否存在而不 获取值的话,可以使用忽略字符"_"。@H_403_0@在修改map值操作时,因为受内存访问安全和哈希算法等缘故,字典被设计成"not adrressable",因此不能直接修改value成员(结构体或数组)。比如:
{ m:=map[int]user{ 1:{ name:"tom",age:19},} m[1].age=1//cannotassigntostructfieldm[1].ageinmap }@H_403_0@但是有两种方式可以实现直接修改map的value成员:
{ m:=map[int]user{ 1:{ name:"tom",} u:=m[1] u.age=1 m[1]=u } { m:=map[int]*user{ 1:{ name:"tom",} m[1].age+=1 }@H_403_0@不能对nil字典进行写操作,但是可以读,比如:
{ varmmap[string]int //p:=m["a"]//ok m["a"]=1//panic:assignmenttoentryinnilmap }@H_403_0@map遍历:
{ //varm=make(map[string]int) varm=map[string]int{} m["route"]=66 m["root"]=67 forkey,value:=rangem{ fmt.Println("Key:",key,"Value:",value) } }@H_403_0@因为map是无序的,如果想按照有序key输出的话,可以先把所有的key取出,然后对key进行排序,再遍历map,比如:
{ m:=make(map[int]int) varkeys[]int fori:=0;i<=5;i++{ m[i]=i } fork,v:=rangem{ fmt.Println("Key:",k,v) } fork:=rangem{ keys=append(keys,k) } sort.Ints(keys) for_,k:=rangekeys{ fmt.Println("Key:",m[k]) } }@H_403_0@并发 @H_403_0@字典不是并发安全的数据结构,如果某个任务正在对字典进行写操作,那么其他任务就不能对该字典执行并发操作(读、写、删除),否则会导致程序崩溃,比如:
m:=make(map[string]int) gofunc(){ for{ m["a"]+=1 time.Sleep(time.Microsecond) } }() gofunc(){ for{ _=m["b"] time.Sleep(time.Microsecond) } }() select{} } 输出: fatalerror:concurrentmapreadandmapwrite@H_403_0@GO语言编译器提供了这种问题(竞争)的检测方式,比如:
#gorun-racefile.go@H_403_0@安全 @H_403_0@可以使用 sync.RWMutex 实现同步,避免并发环境多goroutings同时读写操作,继续完善上面的例子,比如:
{ varlock=new(sync.RWMutex) m:=make(map[string]int) gofunc(){ for{ lock.Lock() m["a"]++ lock.Unlock() time.Sleep(time.Microsecond) } }() gofunc(){ for{ lock.RLock() _=m["b"] lock.RUnlock() time.Sleep(time.Microsecond) } }() select{} }@H_403_0@性能 @H_403_0@在创建字典时预先准备足够的空间有助于提升性能,减少扩张时引发内存动态分配和重复哈希操作,比如:
packagemain import"testing" import"fmt" functest()map[int]int{ m:=make(map[int]int) fori:=0;i<1000;i++{ m[i]=1 } returnm } functestCap()map[int]int{ m:=make(map[int]int,1000) fori:=0;i<1000;i++{ m[i]=1 } returnm } funcBenchmarkTest(t*testing.B){ fori:=0;i<t.N;i++{ test() } } funcBenchmarkTestCap(t*testing.B){ fori:=0;i<t.N;i++{ testCap() } } funcmain(){ resTest:=testing.Benchmark(BenchmarkTest) fmt.Printf("BenchmarkTest\t%d,%dns/op,%dallocs/op,%dB/op\n",resTest.N,resTest.NsPerOp(),resTest.AllocsPerOp(),resTest.AllocedBytesPerOp()) resTest=testing.Benchmark(BenchmarkTestCap) fmt.Printf("BenchmarkTestCap\t%d,resTest.AllocedBytesPerOp()) } 输出: #gorunconmap.go BenchmarkTest 10000,160203ns/op,98allocs/op,89556B/op BenchmarkTestCap20000,65478ns/op,12allocs/op,41825B/op@H_403_0@
@H_403_0@借鉴:<<雨痕笔记>>