如何在遍历常规映射时进行并发映射的更新操作?

huangapple go评论83阅读模式
英文:

How to upsert into concurrent map while iterating over regular map?

问题

我需要一个以string为键,以唯一(无重复项)的int64数组为值的映射,所以我决定使用以下代码,以便值可以充当一个集合。

var customerCatalog = make(map[string]map[int64]bool)

上述映射已经填充了一些数据。现在,我正在尝试通过读取上述常规的customerCatalog映射来填充我的并发映射(concurrent map),但是我遇到了错误:

for k, v := range customerCatalog {
  r.customerCatalog.Upsert(k, v, func(exists bool, valueInMap interface{}, newValue interface{}) interface{} {
    typedNewValue := newValue.([]int64)
    if !exists {
      return typedNewValue
    }
    typedValueInMap := valueInMap.([]int64)
    return append(typedValueInMap, typedNewValue...)
  })
}

这是我遇到的错误。我正在使用如下所示的upsert方法:链接

panic: interface conversion: interface {} is map[int64]bool, not []int64

我做错了什么?

英文:

I need to have a map of string as key and unique (no dupes) int64 array as value so I decided to use something like below so that value can act as a set.

var customerCatalog = make(map[string]map[int64]bool)

Above map is populated with some data in it. Now I am trying to populate my concurrent map in golang by reading above regular customerCatalog map but I am getting error:

for k, v := range customerCatalog {
  r.customerCatalog.Upsert(k, v, func(exists bool, valueInMap interface{}, newValue interface{}) interface{} {
    typedNewValue := newValue.([]int64)
    if !exists {
      return typedNewValue
    }
    typedValueInMap := valueInMap.([]int64)
    return append(typedValueInMap, typedNewValue...)
  })
}

This is the error I am getting. I am using upsert method as shown here

panic: interface conversion: interface {} is map[int64]bool, not []int64

What is wrong I am doing?

答案1

得分: 0

我相信你的问题的一个最小、可重现的示例如下所示(playground):

conMap := cmap.New()

v := map[int64]bool{}
updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
	_ = newValue.([]int64)
	return nil
}

conMap.Upsert("foo", v, updateItemFn)

注意:我已经删除了循环等内容,因为这与 panic 无关。但是你应该注意,由于循环遍历的是 map[string]map[int64]bool 类型,所以 v 的类型将是 map[int64]bool

Upsert 函数在地图中查找键,然后将其和你传入的 value 一起传递给函数。

因此,你的函数接收到的是一个 map[int64]bool,它首先断言这是一个 []int64(这将失败,因为它不是)。要解决这个问题,你需要将 map[int64]bool 转换为 []int64。这可以在调用 Upsert 之前或在你的 UpsertCb 实现中完成,如下所示(playground):

conMap := cmap.New()
conMap.Set("foo", []int64{5, 6})

v := map[int64]bool{
	1: true,
}

updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
	m := newValue.(map[int64]bool)
	a := make([]int64, 0, len(m))
	for k := range m {
		a = append(a, k)
	}
	if valueInMap == nil { // 新值!
		return a
	} else {
		typedValueInMap := valueInMap.([]int64)
		return append(typedValueInMap, a...)
	}
	return a
}

conMap.Upsert("foo", v, updateItemFn)

fmt.Println(conMap.Get("foo"))

上面的示例保持简单,以说明问题;实际上,你可能希望将所有的值添加到一个映射中,以避免重复。

英文:

I believe a minimal, reproducible, example of your issue would be as follows (playground):

conMap := cmap.New()

v := map[int64]bool{}
updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
	_ = newValue.([]int64)
	return nil
}

conMap.Upsert("foo", v, updateItemFn)

Note: I have stripped out the loop etc because that is irrelevant to the panic. However you should note that because the loop iterates over a map[string]map[int64]boolthe type of v will be map[int64]bool.

The Upsert function looks up the key in the map and then passes it and the value you passed in to the function.

So your function is receiving a map[int64]bool and the first thing it does is to assert that this is a []int64 (which will fail because it's not). To fix this you need to convert the map[int64]bool into a []int64. This could be done before calling the Upsert or within your implementation of UpsertCb as shown here (playground):

conMap := cmap.New()
conMap.Set("foo", []int64{5, 6})

v := map[int64]bool{
	1: true,
}

updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
	m := newValue.(map[int64]bool)
	a := make([]int64, 0, len(m))
	for k := range m {
		a = append(a, k)
	}
	if valueInMap == nil { // New value!
		return a
	} else {
		typedValueInMap := valueInMap.([]int64)
		return append(typedValueInMap, a...)
	}
	return a
}

conMap.Upsert("foo", v, updateItemFn)

fmt.Println(conMap.Get("foo"))

The above has been kept simple to demonstrate the point; in reality you may want to add all of the values into a map so as to avoid duplicates.

huangapple
  • 本文由 发表于 2022年3月7日 09:50:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/71375665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定