如何在 Go 中清除地图?

我正在寻找类似于原语类型 map的 c + + 函数 .clear()

或者我应该创建一个新的地图?

更新: 谢谢你的回答。通过查看答案,我意识到有时创建一个新的地图可能会导致一些我们不想要的不一致。考虑下面的例子:

var a map[string]string
var b map[string]string


func main() {
a = make(map[string]string)
b=a
a["hello"]="world"
a = nil
fmt.Println(b["hello"])
}

我的意思是,这仍然不同于 c + + 中的 .clear()函数,它将清除对象中的内容。

111458 次浏览

You should probably just create a new map. There's no real reason to bother trying to clear an existing one, unless the same map is being referred to by multiple pieces of code and one piece explicitly needs to clear out the values such that this change is visible to the other pieces of code.

So yeah, you should probably just say

mymap = make(map[keytype]valtype)

If you do really need to clear the existing map for whatever reason, this is simple enough:

for k := range m {
delete(m, k)
}

Unlike C++, Go is a garbage collected language. You need to think things a bit differently.

When you make a new map

a := map[string]string{"hello": "world"}
a = make(map[string]string)

the original map will be garbage-collected eventually; you don't need to clear it manually. But remember that maps (and slices) are reference types; you create them with make(). The underlying map will be garbage-collected only when there are no references to it. Thus, when you do

a := map[string]string{"hello": "world"}
b := a
a = make(map[string]string)

the original array will not be garbage collected (until b is garbage-collected or b refers to something else).

If you are trying to do this in a loop, you can take advantage of the initialization to clear out the map for you. For example:

for i:=0; i<2; i++ {
animalNames := make(map[string]string)
switch i {
case 0:
animalNames["cat"] = "Patches"
case 1:
animalNames["dog"] = "Spot";
}


fmt.Println("For map instance", i)
for key, value := range animalNames {
fmt.Println(key, value)
}
fmt.Println("-----------\n")
}

When you execute this, it clears out the previous map and starts with an empty map. This is verified by the output:

$ go run maptests.go
For map instance 0
cat Patches
-----------


For map instance 1
dog Spot
-----------
// Method - I , say book is name of map
for k := range book {
delete(book, k)
}


// Method - II
book = make(map[string]int)


// Method - III
book = map[string]int{}

Go 1.18 and above

You can use maps.Clear. The function belongs to the package golang.org/x/exp/maps (experimental and not covered by the compatibility guarantee)

Clear removes all entries from m, leaving it empty.

Example usage:

func main() {
testMap := map[string]int{"gopher": 1, "badger": 2}
maps.Clear(testMap)
fmt.Println(testMap)
    

testMap["zebra"] = 2000
fmt.Println(testMap)
}

Playground: https://go.dev/play/p/qIdnGrd0CYs?v=gotip

If you don't want to depend on experimental packages, you can copy-paste the source, which is actually extremely simple:

func Clear[M ~map[K]V, K comparable, V any](m M) {
for k := range m {
delete(m, k)
}
}

IMPORTANT NOTE: just as with the builtin delete — which the implementation of maps.Clear uses —, this does not remove irreflexive keys from the map. The reason is that for irreflexive keys, by definition, x == x is false. Irreflexive keys are NaN floats and every other type that supports comparison operators but contains NaN floats somewhere.

See this code to understand what this entails:

func main() {
m := map[float64]string{}
m[1.0] = "foo"


k := math.NaN()
fmt.Println(k == k) // false
m[k] = "bar"


maps.Clear(m)
fmt.Printf("len: %d, content: %v\n", len(m), m)
// len: 1, content: map[NaN:bar]


a := map[[2]float64]string{}
a[[2]float64{1.0, 2.0}] = "foo"


h := [2]float64{1.0, math.NaN()}
fmt.Println(h == h) // false
a[h] = "bar"


maps.Clear(a)
fmt.Printf("len: %d, content: %v\n", len(a), a)
// len: 1, content: map[[1 NaN]:bar]
}

Playground: https://go.dev/play/p/LWfiD3iPA8Q

A clear builtin is being currently discussed (Autumn 2022) that, if added to next Go releases, will delete also irreflexive keys.

For the method of clearing a map in Go

for k := range m {
delete(m, k)
}

It only works if m contains no key values containing NaN.

delete(m, k) doesn't work for any irreflexive key (such as math.NaN()), but also structs or other comparable types with any NaN float in it. Given struct{ val float64 } with NaN val is also irreflexive (Quote by blackgreen comment)


To resolve this issue and support clearing a map in Go, one buildin clear(x) function could be available in the new release, for more details, please refer to add clear(x) builtin, to clear map, zero content of slice, ptr-to-array