如何在迭代常规地图时插入并发地图?

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

我需要一个 string 的映射作为键和唯一(没有欺骗)int64 数组作为值,所以我决定使用类似下面的东西,这样值就可以作为一个集合。

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

上面的地图填充了一些数据。现在我正在尝试通过阅读上面的常规 customerCatalog 地图在 golang 中填充我的 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 方法,如图所示 here

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

我做错了什么?

我相信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)

注意:我已经删除了循环等,因为这与恐慌无关。但是您应该注意,因为循环遍历 map[string]map[int64]bool,所以 v 的类型将是 map[int64]bool.

Upsert函数在map中查找key,然后将它和你传入的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 { // New value!
        return a
    } else {
        typedValueInMap := valueInMap.([]int64)
        return append(typedValueInMap, a...)
    }
    return a
}

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

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

以上内容为了说明要点已保持简单;实际上,您可能希望将所有值添加到地图中以避免重复。