GoFrame gmap遍历hashmap listmap treemap使用技巧
来源:脚本之家
时间:2022-12-30 07:41:12 120浏览 收藏
知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个Golang开发实战,手把手教大家学习《GoFrame gmap遍历hashmap listmap treemap使用技巧》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!
文章比较硬核,爆肝2千多字,除了hashmap、listmap、treemap使用技巧阅读还有使用gmap的踩坑之旅,阅读大约需要5~10分钟。
先说结论
map类型
一图胜千言:
实例化示例:
hashMap := gmap.New(true) listMap := gmap.NewListMap(true) treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true)
使用技巧
当我们对返回顺序有要求时不能使用hashmap,因为hashmap返回的是无序列表;
当需要按输入顺序返回结果时使用listmap;
当需要让返回结果自然升序排列时使用treemap
package main import ( "fmt" "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/util/gutil" ) func main() { array := g.Slice{5, 1, 2, 7, 3, 9, 0} hashMap := gmap.New(true) listMap := gmap.NewListMap(true) treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true) // 赋值 for _, v := range array { hashMap.Set(v, v) listMap.Set(v, v) treeMap.Set(v, v) } //打印结果 fmt.Println("hashMap.Keys() :", hashMap.Keys()) fmt.Println("hashMap.Values():", hashMap.Values()) //从打印结果可知hashmap的键列表和值列表返回值的顺序没有规律,随机返回 fmt.Println("listMap.Keys() :", listMap.Keys()) fmt.Println("listMap.Values():", listMap.Values()) //listmap键列表和值列表有序返回,且顺序和写入顺序一致 fmt.Println("treeMap.Keys() :", treeMap.Keys()) fmt.Println("treeMap.Values():", treeMap.Values()) //treemap键列表和值列表也有序返回,但是不和写入顺序一致,按自然数升序返回 }
打印结果
hashMap.Keys() : [5 1 2 7 3 9 0] hashMap.Values(): [2 7 3 9 0 5 1] listMap.Keys() : [5 1 2 7 3 9 0] listMap.Values(): [5 1 2 7 3 9 0] treeMap.Keys() : [0 1 2 3 5 7 9] treeMap.Values(): [0 1 2 3 5 7 9]
为了让大家更好的理解gmap,下面介绍一下gmap的基础使用和一些进阶技巧。
基础概念
GoFrame框架(下文简称gf)提供的数据类型,比如:字典gmap、数组garray、集合gset、队列gqueue、树形结构gtree、链表glist都是支持设置并发安全开关的。
支持设置并发安全开关这也是gf提供的常用数据类型和原生数据类型非常重要的区别
今天和大家分享gf框架中gmap相关知识点
对比sync.Map
go语言提供的原生map不是并发安全的map类型
go语言从1.9版本开始引入了并发安全的sync.Map,但gmap比较于标准库的sync.Map性能更加优异,并且功能更加丰富。
基础使用
- gmap.New(true) 在初始化的时候开启并发安全开关
- 通过 Set() 方法赋值,通过 Sets() 方法批量赋值
- 通过 Size() 方法获取map大小
- 通过 Get() 根据key获取value值
- ...
为了方便大家更好的查看效果,在下方代码段中标明了打印结果
package main import ( "fmt" "github.com/gogf/gf/container/gmap" ) func main() { m := gmap.New(true) // 设置键值对 for i := 0; i < 10; i++ { m.Set(i, i) } fmt.Println("查询map大小:", m.Size()) //批量设置键值对 m.Sets(map[interface{}]interface{}{ 10: 10, 11: 11, }) // 目前map的值 fmt.Println("目前map的值:", m) fmt.Println("查询是否存在键值对:", m.Contains(1)) fmt.Println("根据key获得value:", m.Get(1)) fmt.Println("删除数据", m.Remove(1)) //删除多组数据 fmt.Println("删除前的map大小:", m.Size()) m.Removes([]interface{}{2, 3}) fmt.Println("删除后的map大小:", m.Size()) //当前键名列表 fmt.Println("键名列表:", m.Keys()) //我们发现是无序列表 fmt.Println("键值列表:", m.Values()) //我们发现也是无序列表 //查询键名,当键值不存在时写入默认值 fmt.Println(m.GetOrSet(20, 20)) //返回值是20 fmt.Println(m.GetOrSet(20, "二十")) //返回值仍然是20,因为key对应的值存在 m.Remove(20) fmt.Println(m.GetOrSet(20, "二十")) //返回值是二十,因为key对应的值不存在 // 遍历map m.Iterator(func(k interface{}, v interface{}) bool { fmt.Printf("%v:%v \n", k, v) return true }) //自定义写锁操作 m.LockFunc(func(m map[interface{}]interface{}) { m[88] = 88 }) // 自定义读锁操作 m.RLockFunc(func(m map[interface{}]interface{}) { fmt.Println("m[88]:", m[88]) }) // 清空map m.Clear() //判断map是否为空 fmt.Println("m.IsEmpty():", m.IsEmpty()) }
运行结果
上面介绍的基础使用比较简单,下面介绍进阶使用。
合并 merge
注意:Merge()的参数需要是map的引用类型,也就是传map的取址符。
package main import ( "fmt" "github.com/gogf/gf/container/gmap" ) func main() { var m1, m2 gmap.Map m1.Set("k1", "v1") m2.Set("k2", "v2") m1.Merge(&m2) fmt.Println("m1.Map()", m1.Map()) //m1.Map() map[k1:v1 k2:v2] fmt.Println("m2.Map()", m2.Map()) //m2.Map() map[k2:v2] }
序列化
正如上一篇 GoFrame glist 基础使用和自定义遍历 介绍的,gf框架提供的数据类型不仅支持设置并发安全,也都支持序列化和反序列化。
json序列化和反序列化:序列化就是转成json格式,反序列化就是json转成其他格式类型(比如:map、数组、对象等)
package main import ( "encoding/json" "fmt" "github.com/gogf/gf/container/gmap" ) func main() { // 序列化 //var m gmap.Map m := gmap.New() //必须实例化 只是像上面声明但是不进行实例化,是无法序列化成功的 m.Sets(map[interface{}]interface{}{ "name": "王中阳", "age": 28, }) res, _ := json.Marshal(m) fmt.Println("序列化结果:", res) //打印结果:{"age":28,"name":"王中阳"} // 反序列化 m2 := gmap.New() s := []byte(`{"age":28,"name":"王中阳"}`) _ = json.Unmarshal(s, &m2) fmt.Println("反序列化结果:", m2.Map()) //反序列化结果: map[age:28 name:王中阳] }
踩坑
正如上面代码段中注释提到的:
在进行序列化操作时,必须实例化map
m := gmap.New()
只是声明map而不进行实例化,是无法序列化成功的
var m gmap.Map
过滤空值
package main import ( "fmt" "github.com/gogf/gf/container/gmap" ) func main() { //首先明确:空值和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": false, "k5": 1, }) m1.FilterEmpty() m2.FilterNil() fmt.Println("m1.FilterEmpty():", m1) //预测结果: k5:1 fmt.Println("m2.FilterNil():", m2) //预测结果:除了k2,其他都返回 // 打印结果和预期的一致: //m1.FilterEmpty(): {"k5":1} //m2.FilterNil(): {"k1":"","k3":0,"k4":false,"k5":1} }
打印结果
m1.FilterEmpty(): {"k5":1} m2.FilterNil(): {"k1":"","k3":0,"k4":false,"k5":1}
键值对反转 Flip
package main import ( "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/frame/g" ) func main() { // 键值对反转flip var m gmap.Map m.Sets(map[interface{}]interface{}{ "k1": "v1", "k2": "v2", }) fmt.Println("反转前:", m.Map()) m.Flip() fmt.Println("反转后:", m.Map()) }
打印结果
反转前:{ "k1": "v1", "k2": "v2" } 反转后:{ "v1": "k1", "v2": "k2" }
出栈(随机出栈)
package main import ( "fmt" "github.com/gogf/gf/container/gmap" ) func main() { //pop pops map出栈(弹栈) var m gmap.Map m.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("m.Pop()之后:", m.Map()) //多次测试后发现是随机出栈,不能理所当然的认为按顺序出栈 res := m.Pops(2) //参数是出栈个数 fmt.Println("res:", res) fmt.Println("m.Pops之后:", m.Map()) //多次测试之后发现也是随机出栈 }
运行结果
踩坑
注意:多次测试后发现是随机出栈,不能理所当然的认为按顺序出栈
总结
通过这篇文章,我们了解到:
重点消化一下map遍历时,不同map的特点:
- 1.1 当我们对返回顺序有要求时不能使用hashmap,因为hashmap返回的是无序列表;
- 1.2 当需要按输入顺序返回结果时使用listmap;
- 1.3 当需要让返回结果自然升序排列时使用treemap
gmap的基础使用和进阶使用技巧:反转map、序列化、合并map、出栈等。
gf框架提供的数据结构,比如:字典gmap、数组garray、集合gset、队列gqueue、树形结构gtree、链表glist 都是支持设置并发安全开关的;而且都支持序列化和反序列化,实现了标准库json
数据格式的序列化/反序列化接口。
今天关于《GoFrame gmap遍历hashmap listmap treemap使用技巧》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于golang的内容请关注golang学习网公众号!
-
505 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
467 收藏
-
469 收藏
-
148 收藏
-
250 收藏
-
350 收藏
-
206 收藏
-
467 收藏
-
501 收藏
-
216 收藏
-
284 收藏
-
103 收藏
-
315 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 和谐的煎蛋
- 这篇文章出现的刚刚好,作者大大加油!
- 2023-03-01 12:35:59
-
- 知性的酸奶
- 好细啊,收藏了,感谢作者大大的这篇博文,我会继续支持!
- 2023-01-27 20:02:41
-
- 善良的画板
- 这篇技术文章太及时了,太详细了,写的不错,mark,关注老哥了!希望老哥能多写Golang相关的文章。
- 2023-01-19 22:57:31
-
- 完美的时光
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢师傅分享文章内容!
- 2023-01-13 10:10:03
-
- 稳重的小兔子
- 太细致了,码住,感谢up主的这篇技术文章,我会继续支持!
- 2023-01-02 12:56:04
-
- 潇洒的寒风
- 赞 👍👍,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢作者分享文章内容!
- 2023-01-02 04:21:28
-
- 壮观的心锁
- 这篇技术文章真是及时雨啊,好细啊,感谢大佬分享,码住,关注作者了!希望作者能多写Golang相关的文章。
- 2023-01-01 18:27:25
-
- 温婉的小松鼠
- 真优秀,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢博主分享技术贴!
- 2022-12-31 19:51:16
-
- 彩色的枕头
- 这篇文章太及时了,很详细,受益颇多,码住,关注老哥了!希望老哥能多写Golang相关的文章。
- 2022-12-31 11:12:28