【问题标题】:Updating a key in a map, whilst iterating over that map更新地图中的键,同时迭代该地图
【发布时间】:2019-01-07 17:57:39
【问题描述】:

我想使用 URL 参数将密钥从一个名称更新为另一个名称。我有代码,但输出不正确。见下文。

这是地图

var data map[string][]string

我正在调用的函数的PUT方法

r.HandleFunc("/updatekey/{key}/{newkey}", handleUpdateKey).Methods("PUT")

handleUpdateKey 函数,它被记录下来准确解释它在做什么。

func handleUpdateKey(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)

k := params["key"] //get url params
nk := params["newkey"]

s := make([]string, len(data[k])) //create slice of string to store map variables
for i := range data {             //range over the data map
    fmt.Fprintf(w, i)
    if k != i { //check if no keys exist with URL key param
        fmt.Fprintf(w, "That KEY doesn't exist in memory")
        break //kill the loop
    } else { //if there is a key the same as the key param
        for _, values := range data[i] { //loop over the slice of string (values in that KEY)
            s = append(s, values) //append all those items to the slice of string
        }

        delete(data, k) //delete the old key

        for _, svalues := range s { //loop over the slice of string we created earlier
            data[nk] = append(data[nk], svalues) //append the items within the slice of string, to the new key... replicating the old key, with a new key name
        }
    }
}
}

下面应该将该 KEY 的所有值分配给一个字符串切片,我们稍后会对其进行迭代并添加到新的 KEY 中。这行得通,但是,输出如下,显然不正确

KEY: catt: VALUE: 
KEY: catt: VALUE: 
KEY: catt: VALUE: zeus
KEY: catt: VALUE: xena

旧输出:

KEY: dog: VALUE: zeus
KEY: dog: VALUE: xena

正确的新输出:

KEY: catt: VALUE: zeus
KEY: catt: VALUE: xena

【问题讨论】:

  • 在迭代地图时不要改变它。您可以更改值,但不应添加或删除任何项目。
  • 另外,如果您尝试修改地图中的 ,您应该重新考虑您的设计。正如您从必须删除并重新添加项目以伪造更改键所看到的那样,映射键是不可变的。也许您只想要一个项目,其中每个项目都有键字段?
  • 你的意思是像一个结构吗? Key和Value存储在里面?
  • 是的,就像一个结构体。

标签: for-loop go


【解决方案1】:

在大多数语言中,更改您正在迭代的结构会导致奇怪的事情发生。特别是地图。你必须另寻出路。

幸运的是,根本不需要迭代。您的循环只是一个大的 if/else 语句。如果键匹配,做一些事情。如果没有,请执行其他操作。因为这是一个map,所以不用迭代查找key,直接查找即可。也不需要为了复制地图值而进行所有费力的循环。

if val, ok := data[k]; ok {
    // Copy the value
    data[nk] = val
    // Delete the old key
    delete(data, k)
} else {
    fmt.Fprintf(w, "The key %v doesn't exist", k)
}

最后,避免在函数中使用全局变量。如果函数可以更改全局变量,则很难理解函数对程序的影响。应该将data 传递给函数以使其清晰。

func handleUpdateKey(w http.ResponseWriter, r *http.Request, data map[string][]string)

【讨论】:

  • 非常感谢!感谢您的帮助:) 我现在正在尝试删除一个值...如前所述,您永远不应该通过范围循环来改变地图,那么我将如何使用这种方法呢? if v, ok := data[k]; ok { data[k] = append(data[k][:i], data[k][i+1:]...) fmt.Fprintf(w, "KEY: %v: VALUE: %v was deleted successfully", k, v)
  • @RossBown 这只是您需要担心的键。您可以随意更改这些值。但是这里没有更多的迭代,所以你很安全。目前还不清楚你想在那里做什么。问另一个问题。
  • 我只想从 MAP 中的字符串切片中删除一个值...我是否遍历这些值并删除与 URL 中的参数匹配的那个...或者是否存在更好的方法?从我在文档上看到的内容来看,没有办法通过它的名称循环并删除该值,而是您必须找到索引并删除它。
  • @RossBown 从切片中删除值与在映射中更改其键是一个单独的问题。再问一个关于这个的问题。
猜你喜欢
  • 1970-01-01
  • 2022-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 1970-01-01
  • 2020-10-31
相关资源
最近更新 更多