golang de-reference a map - go

Here is a sample code that creates a Map of string keys having value of bool.
myMap := make(map[string]bool)
myMap["Jan"] = true
myMap["Feb"] = false
myMap["Mar"] = true
After doing some operation on this map, I want to delete it. I don't want to use for loop to iterate through each key and delete.
If I do re-initialize myMap again (like following), does it de-references the original and subject to garbage collection?
myMap = make(map[string]bool)

Golang FAQ on garbage collection:
Each variable in Go exists as long as there are references to it. If
the compiler cannot prove that the variable is not referenced after
the function returns, then the compiler must allocate the variable on
the garbage-collected heap to avoid dangling pointer errors.
In case there are no references used for the current map it will be garbage collected by the language. But for deleting a map There is no process other than looping over it and delete the keys one by one. as
myMap := make(map[string]bool)
for k, _ := range myMap{
delete(myMap, k)
}
If you re-initialze the map using make it will not going to de-reference the same it will clear the map but will not dereference it. If you check for its len it will become zero
package main
import (
"fmt"
)
func main() {
myMap := make(map[string]bool)
myMap["Jan"] = true
myMap["Feb"] = false
myMap["Mar"] = true
fmt.Println(len(myMap))
myMap = make(map[string]bool)
fmt.Println(len(myMap))
}
Along with that if you prints the address it points to same address.
fmt.Printf("address: %p \n", &myMap)
myMap = make(map[string]bool)
fmt.Printf("address: %p ", &myMap)
Playground Example

Related

Remove all map key in Golang [duplicate]

I'm looking for something like the c++ function .clear() for the primitive type map.
Or should I just create a new map instead?
Update: Thank you for your answers. By looking at the answers I just realized that sometimes creating a new map may lead to some inconsistency that we don't want. Consider the following example:
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"])
}
I mean, this is still different from the .clear() function in c++, which will clear the content in the object.
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).
// 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
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
-----------

Golang how to create map to pointer to slice using make

I want to create a dynamically initialized bitmap data structure. I'm trying to use the golang maps for this:
type Register map[bool]*[]bool
The way I'm initializing the map is:
register := make(Register)
register[true] := make(*[]bool, len(arr)) // arr is the array for which i want to create the bitmap
This obviously creates compilation issue with the error:
error: cannot make type *[]bool
I have also tried using the pointer syntax:
register[true] = &(make([]bool, len(arr)))
Which gives me the error:
cannot take the address of make([]bool, len(arr))
The reason I want the map values to be *[]bool is so that the write back to the map stays sane and in-place.
While go doesn't complain about map[bool]*[]bool hence its a valid type.
If it is valid the what is the idomatic way to use it in the fashion I want to. If not then what would be the alternate way?
Use the following code to create a pointer to a slice:
register := make(Register)
s := make([]bool, len(arr)) // create addressable slice value s.
register[true] = &s
You can use new to eliminate the variable declaration, but this approach does not reduce the number of lines of code and it adds another map index operation.
register := make(Register)
register[true] = new([]bool)
*register[true] = make([]bool, len(arr))
Declare a function to move the assignment on to a single line:
func makeSlice(n int) *[]bool {
s := make([]bool, len(arr))
return &s
}
...
register := Register{true: makeSlice(len(arr))}
Because the map keys have two possible values, true and false, you might be able to simplify the code by using a struct instead of a map:
type Register struct {
t, f []bool
}
register := Register{t: make([]bool, len(arr))}
The struct fields in register are addressable, so you can use &register.t to get the *[]bool.
A variation on this theme is to use an array:
type Register [2][]bool
register := Register{1: make([]bool, len(arr))}
If you modify the slice elements only and not the slice value, then there's no need to use a pointer to the slice.
type Register map[bool][]bool
register := make(Register)
register[true] := make([]bool, len(arr))
If you do modify the slice value, the map[bool][]bool may be more efficient and easier to use. The application will need to assign back to the map when the slice value is modified, but you eliminate the indirections.
Another option is using the new function:
package main
import "fmt"
func main() {
type Register map[bool]*[]bool
register := make(Register)
register[true] = new([]bool)
// main.Register{true:(*[]bool)(0xc000004078)}
fmt.Printf("%#v\n", register)
}
https://golang.org/pkg/builtin#new

Is json marshalling of map stable in Go? [duplicate]

This question already has answers here:
How to produce JSON with sorted keys in Go?
(2 answers)
Closed 3 years ago.
I am writing code that will check if data changed based on a comparison of json.Marshaled hashes of maps. I've created small code to produce what I am doing in abstracted way (available also in playground)
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
)
func main() {
fmt.Println("Hello, playground")
a := make(map[string]string)
a["a"] = "a1"
a["b"] = "b2"
sa, _ := json.Marshal(a)
ha := GenerateSHA256Hash(string(sa))
b := make(map[string]string)
b["a"] = "a1"
b["b"] = "b2"
sb, _ := json.Marshal(b)
hb := GenerateSHA256Hash(string(sb))
fmt.Println(ha)
fmt.Println(hb)
fmt.Println(ha == hb)
}
func GenerateSHA256Hash(s string) string {
hasher := sha256.New()
hasher.Write([]byte(s))
return hex.EncodeToString(hasher.Sum(nil))
}
But I recall that order of maps are unordered and in Golang spec it's written that
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.
So, in the code above I am building map, in the same way, each time and not accessing it concurrently during json.Marshalling.
Question: Will the hashes, produced in such manner, be always equal? Or will this approach be stable?
Go spec in this case is irrelevant since it's a details of the Go standard library (the encoding/json module)
As of this very moment it's implemented as
// Extract and sort the keys.
keys := v.MapKeys()
sv := make([]reflectWithString, len(keys))
for i, v := range keys {
sv[i].v = v
if err := sv[i].resolve(); err != nil {
e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error()))
}
}
sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s })
Additionally, given the encoding/json documentation says
The map keys are sorted and used as JSON object keys by applying the following rules, subject to the UTF-8 coercion described for string values above:
it's safe to expect the same hash until at least Go 2.

Memory usage: nil interface{} vs struct{}

I'm trying to learn more regarding memory usage.
Doing some tests with interface{} and struct{} slices, I noticed that a slice of struct{} doesn't allocate any memory whereas a slice of interface{} does. It doesn't make so much sense to me, I'm actually expecting the same behavior (ie. both allocate nothing). Anyway I couldn't find any explanation regarding this particular case.
Could someone explain me why this happens?
package main
import (
"runtime"
"fmt"
)
func main() {
// Below is an example of using our PrintMemUsage() function
// Print our starting memory usage (should be around 0mb)
fmt.Println("Start")
PrintMemUsage()
fmt.Println("")
structContainer := make([]struct{}, 1000000)
for i := 0; i<1000000; i++ {
structContainer[i] = struct{}{}
}
fmt.Println("With 1kk struct{}")
PrintMemUsage()
fmt.Println("")
nilContainer := make([]interface{}, 1000000)
for i := 0; i<1000000; i++ {
nilContainer[i] = nil
}
fmt.Println("With 1kk nil interface{}")
PrintMemUsage()
fmt.Println("")
}
// PrintMemUsage outputs the current, total and OS memory being used. As well as the number
// of garage collection cycles completed.
func PrintMemUsage() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
fmt.Printf("Alloc = %v KiB", bToMb(m.Alloc))
fmt.Printf("\tTotalAlloc = %v KiB", bToMb(m.TotalAlloc))
fmt.Printf("\tSys = %v KiB", bToMb(m.Sys))
fmt.Printf("\tNumGC = %v\n", m.NumGC)
}
func bToMb(b uint64) uint64 {
return b / 1024
}
Playground link.
A variable of type interface{} can hold any value. E.g. it can hold the integer 8, it can hold the string value "hi", it can hold the struct value image.Point{X: 1, Y: 2} and pretty much everything else.
If you allocate a slice having interface{} as its element type, memory have to be allocated so that you can store any values in its elements. When using make() to allocate it, all its elements will get the zero value of the element type (which is nil for the interface{}), but memory still has to be allocated else you couldn't set elements later on.
On the other hand, the empty struct struct{} has no fields, it cannot hold any values (other than struct{}). When you allocate a slice having struct{} as its element type, memory does not need to be allocated because you won't be able to store anything in it that would require memory. So it's a simple and clever optimization not to allocate memory for such a type.
This is because an empty struct contains no value.
This is not very useful for arrays or slices. But it is useful for maps. A map without value is like a set. You can insert keys and test if they are present. The absence of value save space as you discovered.

Difference in behavior between slices and maps

A related questions is here https://stackoverflow.com/a/12965872/6421681.
In go, you can do:
func numsInFactorial(n int) (nums []int) {
// `nums := make([]int)` is not needed
for i := 1; i <= n; i++ {
nums = append(nums, i)
}
return
}
However,the following doesn't work:
func mapWithOneKeyAndValue(k int, v int) (m map[int]int) {
m[k] = v
return
}
An error is thrown:
panic: assignment to entry in nil map
Instead, you must:
func mapWithOneKeyAndValue(k int, v int) map[int]int {
m := make(map[int]int)
m[k] = v
return
}
I can't find the documentation for this behavior.
I have read through all of effective go, and there's no mention of it there either.
I know that named return values are defined (i.e. memory is allocated; close to what new does) but not initialized (so make behavior isn't replicated).
After some experimenting, I believe this behavior can be reduced into understanding the behavior of the following code:
func main() {
var s []int // len and cap are both 0
var m map[int]int
fmt.Println(s) // works... prints an empty slice
fmt.Println(m) // works... prints an empty map
s = append(s, 10) // returns a new slice, so underlying array gets allocated
fmt.Println(s) // works... prints [10]
m[10] = 10 // program crashes, with "assignment to entry in nil map"
fmt.Println(m)
}
The issue seems that append likely calls make and allocates a new slice detecting that the capacity of s is 0. However, map never gets an explicit initialization.
The reason for this SO question is two-pronged. First, I would like to document the behavior on SO. Second, why would the language allow non-initializing definitions of slice and map? With my experience with go so far, it seems to be a pragmatic language (i.e. unused variables lead to compilation failure, gofmt forces proper formatting), so it would make sense for it to prevent the code from compiling.
Try to assign in nil slice by index - you will get "panic: runtime error: index out of range" (example: https://play.golang.org/p/-XHh1jNyn5g)
The only reason why append function works with nil, is that append function can do reallocation for the given slice.
For example, if you trying to to append 6th element to slice of 5 elements with current capacity 5, it will create the new array with new capacity, copy all the info from old one, and swap the data array pointers in the given slice. In my understanding, it is just golang implementation of dynamic arrays.
So, the nil slice is just a special case of slice with not enough capacity, so it would be reallocated on any append operation.
More details on https://blog.golang.org/go-slices-usage-and-internals
From https://blog.golang.org/go-maps-in-action
A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that. To initialize a map, use the built in make function
It seems like a nil map is considered a valid empty map and that's the reason they don't allocate memory for it automatically.

Resources