前言很多GO初学者都被Go语言中map的乱序“坑”过。尤其是PHP转Go的朋友们~本文将为大家介绍一下:GoFrame的gmap相比Go原生的map有什么优势?为什么天生就支持排序和有序遍历呢?如何?GoFrame的gmap有哪些使用技巧?先说结论吧。GoFrame提供的gmap字典类型包含了多种数据结构的地图容器:HashMap、TreeMap和ListMap。其中TreeMap支持排序,TreeMap和ListMap支持有序遍历。Tips我们在使用GoFrame的gmap时,需要结合自己的场景使用合适的地图容器:当我们对返回顺序有要求时,不能使用HashMap,因为HashMap返回的是无序列表;当我们需要按输入顺序返回结果时使用ListMap;当需要对返回结果进行自然升序排列时使用TreeMap;注:gmap的实例化默认为HashMap类型:hashMap:=gmap.New(true)一张图顶一千字GoFramegmap基本介绍:支持并发安全开关选项的地图容器,最常用的数据结构.该模块包含多个数据结构的映射容器:HashMap、TreeMap和ListMap。实例化示例:hashMap:=gmap.New(true)listMap:=gmap.NewListMap(true)treeMap:=gmap.NewTreeMap(gutil.ComparatorInt,true)实用知识包mainimport("fmt""github.com/gogf/gf/v2/container/gmap""github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/util/gutil")funcmain(){array:=g.切片{1,5,2,3,4,6,8,7,9}hashMap:=gmap.New(true)listMap:=gmap.NewListMap(true)treeMap:=gmap.NewTreeMap(gutil.ComparatorInt,true)for_,v:=rangearray{hashMap.Set(v,v)}for_,v:=rangearray{listMap.Set(v,v)}for_,v:=rangearray{treeMap.Set(v,v)}fmt.Println("HashMapKeys:",hashMap.Keys())//HashMapKeys:[791524638]fmt.Println("HashMapValues:",hashMap.Values())//HashMapValues:[679152438]//从打印结果可以看出hashmap的keylist和valuelist返回值的顺序是无规律的,随机返回fmt.Println("ListMapKeys:",listMap.Keys())//ListMapKeys:[152346879]fmt.Println("ListMapValues:",listMap.Values())//ListMapValues:[152346879]//listmap键列表和值列表按顺序返回,顺序和写的顺序一致fmt.Println("TreeMapKeys:",treeMap.Keys())//TreeMapKeys:[123456789]fmt.Println("TreeMapValues:",treeMap.Values())//TreeMapValues:[123456789]//treemap的key列表和value列表也是按顺序返回的,但是写的顺序不一致,按照自然数升序返回}printresult通过打印结果,我们可以发现:hashmap的keylist和valuelist返回值的顺序是没有规律的,listmapkeylist和valuelist是随机返回的,顺序和写的顺序一致。treemapkeylist和valuelist也是按顺序返回的,但是和写的顺序不一样,是按照自然数升序返回的。这也佐证了我开篇提到的使用技巧为了让大家更好的了解gmap,下面介绍gmap的基本使用和一些进阶技巧。基本概念GoFrame框架(以下简称gf)提供的数据类型,如:字典gmap、数组garray、集合gset、队列gqueue、树结构gtree、链表glist等,都支持设置并发安全开关。支持设置并发安全开关这也是gf提供的普通数据类型与原生数据类型的重要区别之一。与sync.Map相比,Go语言提供的原生map不是并发安全的map类型。Go语言从1.9版本开始就引入了并发安全的sync.Map,但是gmap比标准库的sync.Map性能更好,功能更丰富。goos:linuxgoarch:amd64Benchmark_GMapSet-410000000209ns/op15B/op0allocs/opBenchmark_SyncMapSet-43000000451ns/op67B/op3allocs/opBenchmark_GMapGet-43000000066.4ns/opcMapcBop/opallocs-43000000036.0ns/op0B/op0allocs/opBenchmark_GMapRemove-410000000207ns/op0B/op0allocs/opBenchmark_SyncMapRmove-43000000042.4ns/op0B/op0allocs/op对性能测试感兴趣你可以详细阅读官方文档[2]的介绍,这不是本文的重点。基本使用gmap.New(true)在初始化时开启并发安全开关通过Set()方法赋值,通过Sets()方法批量赋值通过Size()方法获取地图大小根据获取值通过Get()获取key……更多操作可以直接查看下方代码示例,欢迎大家实践。为了方便大家更好的查看结果,在下面的代码段中标注了打印结果::=gmap.New(true)//为i设置键值对:=0;我<10;i++{m.Set(i,i)}fmt.Println("Querymapsize:",m.Size())//批量设置键值对m.Sets(map[interface{}]interface{}{10:10,11:11,})//当前map的值fmt.Println("当前map值:",m)fmt.Println("查询是否有键值对:",m.Contains(1))fmt.Println("根据key取值:",m.Get(1))fmt.Println("删除数据",m.Remove(1))//删除多组数据fmt.Println("删除前的地图大小:",m.Size())m.Removes([]interface{}{2,3})fmt.Println("删除后的地图大小:",m.Size())//当前键名列表fmt.Println("键名列表:",m.Keys())//我们发现它是一个无序列表fmt.Println("keyvaluelist:",m.Values())//我们发现它也是一个无序列表//查询键名,当键值不存在写入默认值fmt.Println(m.GetOrSet(20,20))//返回值为20fmt.Println(m.GetOrSet(20,"Twenty"))//返回值还是20,因为key对应值存在m.Remove(20)fmt.Println(m.GetOrSet(20,"Twenty"))//返回值为二十,因为key对应的值不存在//遍历mapm.Iterator(func(kinterface{},vinterface{})bool{fmt.Printf("%v:%v\n",k,v)returntrue})//自定义写锁操作m.LockFunc(func(mmap[interface{}]interface{}){m[88]=88})//自定义读锁操作m.RLockFunc(func(mmap[interface{}]interface{}){fmt.Println("m[88]:",m[88])})//清除地图m.Clear()//判断地图是否为空介绍的基本用法比较简单。下面介绍merge的高级用法注意:Merge()的参数需要是map的引用类型,即参数需要传递map的地址。packagemainimport("fmt""github.com/gogf/gf/v2/container/gmap")funcmain(){varm1,m2gmap.Mapm1.Set("k1","v1")m2.Set("k2","v2")m1.Merge(&m2)fmt.Println("m1.Map()",m1.Map())//m1.Map()map[k1:v1k2:v2]fmt.Println("m2.Map()",m2.Map())//m2.Map()map[k2:v2]}打印结果的序列化就像上篇文章介绍的GoFrameglist基本使用和自定义遍历[3]是的,gf框架提供的数据类型不仅支持设置并发安全开关,还支持序列化和反序列化。json序列化和反序列化:序列化就是转成json格式,反序列化就是把json转成其他格式类型(如:map、array、object等)packagemainimport("encoding/json""fmt""github.com/gogf/gf/v2/container/gmap")funcmain(){//序列化//varmgmap.Mapm:=gmap.New()//必须像上面的语句一样实例化但没有实例化m.Sets(map[interface{}]interface{}{"name":"王中阳","age":28,})res,_:=json.Marshal(m)fmt.Println("序列化结果:",string(res))//打印结果:{"age":28,"name":"王中阳"}//反序列化m2:=gmap.New()s:=[]byte(`{"age":28,"name":"王中阳"}`)_=json.Unmarshal(s,&m2)fmt.Println("反序列化结果:",m2.Map())//反序列化结果:map[age:28name:WangZhongyang]}打印结果踩坑,上面代码段注释掉://varmgmap.Mapmustinstantiatemapmwhenperformingserializationoperations:=gmap.New()只是声明地图而不实例化它。它无法成功序列化。不同的。零是未定义的;而空值包括空字符串、false、0等。与nil不同,nil是未定义的;而空值包括空字符串、false、0等m1:=gmap.NewFrom(map[interface{}]interface{}{"k1":"","k2":nil,"k3":0,"k4":false,"k5":1,})m2:=gmap.NewFrom(map[interface{}]interface{}{"k1":"","k2":nil,"k3":0,"k4":假,"k5":1,})m1.FilterEmpty()m2。FilterNil()fmt.Println("m1.FilterEmpty():",m1)//预测结果:k5:1fmt.Println("m2.FilterNil():",m2)//预测结果:返回除k2以外的所有}打印结果也有一个非常有用的功能,key-valuepairsTurn:key-valuepairreversalFlippackagemainimport("github.com/gogf/gf/v2/container/gmap""github.com/gogf/gf/v2/frame/g")funcmain(){//key-valueForreverseflipvarmgmap.Mapm.Sets(map[interface{}]interface{}{"k1":"v1","k2":"v2",})fmt.Println("Beforereversal:",m.Map())m.Flip()fmt.Println("Afterreversal:",m.Map())}打印结果出栈包mainimport("fmt""github.com/gogf/gf/v2/container/gmap")funcmain(){//pop将地图弹出栈(popstack)varmgmap.Mapm.Sets(map[interface{}]interface{}{1:1,2:2,3:3,4:4,5:5,})fmt.Println("在m.Pop():",m.Map())key,value:=m.Pop()fmt.Println("key:",key)fmt.Println("value:",value)fmt.Println("afterm.Pop():",m.Map())//经过多次测试,发现是随机弹出的stack,不能想当然的认为是有序的Popres:=m.Pops(2)//参数为弹出的个数fmt.Println("res:",res)fmt.Println("afterm.Pops:",m.Map())//多次测试发现也是随机出栈}运行结果踩坑注:多次测试发现出栈随机的,不能想当然的按顺序出栈,我们想想原因:其实很简单,因为gmap.Map对象的底层实现是hashmap,是无序的。当然,它不可能能够按顺序将其从堆栈中弹出。总结之后,我们来回顾一下本文的重点:当我们使用GoFrame的gmap时,需要结合自己的场景使用合适的map容器:当我们对返回顺序有要求时,不能使用HashMap,因为HashMap返回的是一个无序列表;当需要按输入顺序返回结果时使用ListMap;当返回的结果需要按自然升序排列时使用TreeMap;gmap的实例化默认为HashMap类型:hashMap:=gmap.New(true)gmap的基础和高级使用技巧:reversemap,serialize,mergemap,stack等gf框架提供的数据结构,如as:字典gmap、数组garray、集合gset、队列gqueue、树结构gtree、链表glist都支持设置并发安全开关;并且都支持序列化和反序列化,实现标准库json数据格式的序列化/反序列化接口。相关文章[1]#Go易错知识点总结:Go地图中如何实现排序:https://juejin.cn/post/7131717990558466062#heading-25[2]官方文档介绍:https://goframe.org/pages/viewpage.action?pageId=30736719[3]GoFrameglist的基本使用和自定义遍历:https://juejin.cn/post/7101515355062796296》,作者“王中阳围棋”,可通过以下二维码关注,转载本文请联系《程序员升级打怪之旅》公众号。
