Golang实践录:map的几个使用示例
Posted 李迟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang实践录:map的几个使用示例相关的知识,希望对你有一定的参考价值。
本文针对 Golang 的 Map 实现几个简单示例。这些都是在实际工程中使用到的。
基本使用
map 是一种无序的基于key-value的数据结构,Golang 的 map 是引用类型,因此必须初始化才能使用。
下面给出几种初始化形式示例:
var m map[string]int
m = make(map[string]int)
m := make(map[string]int)
var FuncMap = map[string]func(int, string)
...
var allMap map[string]PersonInfo_t
allMap = make(map[string]PersonInfo_t)
增加:
m["latelee"] = 250
删除:
delete(m, "latelee")
查询 key 是否存在:
if v, ok := allMap[id]; ok
...
遍历:
for k, v := range allMap
...
实践
对基本使用有一定了解后,需根据实际应用场合使用,本节列举几个示例:
函数调用
需求:一个命令模块,根据不同的命令名称,调用不同的函数。
可用数组实现,但要遍历查询;也可用if
判断,如果用 map 实现,从代码整洁和维护角度看,都是个不错的选择。定义的FuncMap
,key为命令,value为函数指针,具体代码如下:
// 全局变量,映射,可由其它包使用
// 简单定义map的函数指针
var FuncMap = map[string]func(int, string)
"111": map1,
"222": map2,
func map1(a int, b string)
fmt.Println("111", a, b)
func map2(a int, b string)
fmt.Println("222", a, b)
func test1(id string)
a := 250
b := "25.250"
if fn, ok := FuncMap[id]; ok
fn(a, b)
else
fmt.Println(id, "not found func")
输出结果:
111 250 25.250
222 250 25.250
333 not found func
多线程的使用
需求:工程中有较多线程(Golang中实际上协程),对同一个 map 有读、写的操作,此时,普通的 map 则无法适应,需使用sync.Map
,使用也简单,主要函数有:
添加:g_syncMap.Store
。
删除:g_syncMap.Delete(key)
。
测试代码如下:
// sync.Map使用
var g_syncMap sync.Map
func showSyncMap()
// 遍历打印,不做死循环
g_syncMap.Range(func(k, v interface) bool
v1 := v.(string)
fmt.Printf("key: %v -> %v\\n", k, v1)
return true
)
func test2()
// 存
g_syncMap.Store(1, "111")
g_syncMap.Store(2, "222")
g_syncMap.Store(3, "333")
showSyncMap()
// 删除
g_syncMap.Delete(1)
showSyncMap()
g_syncMap.Store(3, "333_111") // 重复写同一个key,会更新为新的
showSyncMap()
//Load 方法,获得value
if v, ok := g_syncMap.Load(2); ok
fmt.Println("Load ->", v)
//LoadOrStore方法,获取或者保存
//参数是一对key:value,如果该key存在且没有被标记删除则返回原先的value(不更新)和true;
// 不存在则store,返回该value 和false
if vv, ok := g_syncMap.LoadOrStore(1, "c"); !ok // 前面删除1了,这里重新保存
fmt.Println("save new", vv)
if vv, ok := g_syncMap.LoadOrStore(2, "c"); ok // 2 一直存在
fmt.Println("exist", vv, ok)
showSyncMap()
输出结果如下:
key: 1 -> 111
key: 2 -> 222
key: 3 -> 333
key: 2 -> 222
key: 3 -> 333
key: 2 -> 222
key: 3 -> 333_111
Load -> 222
save new c
exist 222 true
key: 1 -> c
key: 2 -> 222
key: 3 -> 333_111
多 key 单独查询
需求:某种数据有很多个字段,可以根据其中的一些字段查询的对象。如某一人员信息,有ID、code代码、名称等,可以根据ID查人员信息,也可以根据code代码查,还可以根据名称查(假定名称不重复)。
由于 map 不能有多个 key,因此使用多个 map 映射。设主信息的 allMap 的 key 为 ID,value 为人员信息。另外有若干辅助 map,cMap 的 key 为 code,value为ID;hMap类似,key 为 hex 码,value 为 ID。查询时,先查辅助 map,得到 ID值,再查主 map。
示例代码:
type PersonInfo_t struct
id string
hex string
code string
name string
age int
var allMap map[string]PersonInfo_t
var cMap map[string]string
var hMap map[string]string
func findFromItem(item string) (ret PersonInfo_t)
id := item // default id
if len(item) == 4 // hex
id = hMap[item]
else if len(item) == 6 // code
id = cMap[item]
if v, ok := allMap[id]; ok
fmt.Printf("found %v\\n", id)
return v
return PersonInfo_t
func showMap(allMap map[string]PersonInfo_t)
var keys []string
for k, _ := range allMap
keys = append(keys, k)
// 进行数组的排序
sort.Strings(keys)
// 遍历数组就是有序的了
for _, k := range keys
fmt.Printf("v: %v\\n", allMap[k])
func multiMap()
allMap = make(map[string]PersonInfo_t)
cMap = make(map[string]string)
hMap = make(map[string]string)
for i := 0; i < 10; i++
var tmp PersonInfo_t
tmp.id = fmt.Sprintf("id_%02d", i)
tmp.code = fmt.Sprintf("C00%03d", i)
tmp.hex = fmt.Sprintf("H%03d", i)
tmp.name = fmt.Sprintf("foo_%d_bar", i)
tmp.age = 20
// 总的
allMap[tmp.id] = tmp
// 存储id的
cMap[tmp.code] = tmp.id
hMap[tmp.hex] = tmp.id
//showMap(allMap)
id := "id_00"
fmt.Printf("%v: %v\\n", id, allMap[id])
id = "id_100"
fmt.Printf("%v: %v\\n", id, allMap[id])
id = "H007"
fmt.Printf("%v: %v\\n", id, findFromItem(id))
id = "H017"
fmt.Printf("%v: %v\\n", id, findFromItem(id))
id = "C00005"
fmt.Printf("%v: %v\\n", id, findFromItem(id))
输出结果:
id_00: id_00 H000 C00000 foo_0_bar 20
id_100: 0
found id_07
H007: id_07 H007 C00007 foo_7_bar 20
H017: 0
found id_05
C00005: id_05 H005 C00005 foo_5_bar 20
多 key 查询
需求:某种数据有很多个字段,由其中的两个字段共同决定查询的对象。接上一例子,假定必须有code代码和hex代码才能确认人员信息。在设计上,将这两个字段合并作为key即可。
代码如下:
var mMap map[string]PersonInfo_t
func findFromM(code, hex string) (ret PersonInfo_t)
key := fmt.Sprintf("%v_%v", code, hex)
if v, ok := mMap[key]; ok
return v
return PersonInfo_t
func mkMap()
mMap = make(map[string]PersonInfo_t)
for i := 0; i < 10; i++
var tmp PersonInfo_t
tmp.id = fmt.Sprintf("id_%02d", i)
tmp.code = fmt.Sprintf("C00%03d", i)
tmp.hex = fmt.Sprintf("H%03d", i)
tmp.name = fmt.Sprintf("foo_%d_bar", i)
tmp.age = 20
// 多个key
key := fmt.Sprintf("%v_%v", tmp.code, tmp.hex)
mMap[key] = tmp
showMap(allMap)
code := "C00000"
hex := "H000"
fmt.Printf("%v & %v: %v\\n", code, hex, findFromM(code, hex))
code = "C00000"
hex = "H111" // 不存在的
fmt.Printf("%v & %v: %v\\n", code, hex, findFromM(code, hex))
输出结果:
C00000 & H000: id_00 C00000 H000 foo_0_bar 20
C00000 & H111: 0
小结
对于多 key 单独查询的场合,是典型的用空间换时间的思路,如果使用时间换空间,则可建立数组,遍历查询,查询条件即为不同的字段,数量在万级别以下,可能没有明显差别,但到百万级别,耗时就比较大了,因此,是否真正需要应用 map,还得自行评估。实际上,笔者2种方式都有使用到。
以上是关于Golang实践录:map的几个使用示例的主要内容,如果未能解决你的问题,请参考以下文章