📜 ⬆️ ⬇️

Passing type map to function

Recently, I skipped an article about how different simple types and slices in memory are arranged. From this article, we learned why a slice passed “by value” to a function is passing a slice by reference only until the slice inside the function requires reallocation in memory as its capacity increases. If inside the capacity function of this slice is changed, and it was passed "by value" and not as a pointer, then the slice starts to refer to a completely different array, not the one that will be further used in the calling function.

Such a slice feature can generate "random" errors in the logic of the program at run time, if the programmer did not take this into account.

I have a question, is there a similar situation with the type of map ? After all, it also has capacity, and it can also change allocation in memory as the number of pairs of values ​​grows.

And I did a little experiment by writing this code:
')
package main import ( "fmt" ) type myMap map[string]string func main() { mymap := make(myMap, 1) mymap["firstKey"] = "firstValue" fmt.Printf("Init method nop: Address = %p Len = %d\n", &mymap, len(mymap)) mymap.grow() fmt.Printf("Growed method nop: Address = %p Len = %d\n", &mymap, len(mymap)) mymap = make(myMap, 1) mymap["firstKey"] = "firstValue" fmt.Printf("Init method p: Address = %p Len = %d\n", &mymap, len(mymap)) (&mymap).growp() fmt.Printf("Growed method p: Address = %p Len = %d\n", &mymap, len(mymap)) mymap = make(myMap, 1) mymap["firstKey"] = "firstValue" fmt.Printf("Init func nop: Address = %p Len = %d\n", &mymap, len(mymap)) fgrow(mymap) fmt.Printf("Growed func nop: Address = %p Len = %d\n", &mymap, len(mymap)) mymap = make(myMap, 1) mymap["firstKey"] = "firstValue" fmt.Printf("Init func p: Address = %p Len = %d\n", &mymap, len(mymap)) fgrowp(&mymap) fmt.Printf("Growed func p: Address = %p Len = %d\n", &mymap, len(mymap)) } func (m myMap) grow() { for i := 1; i < 1000000; i++ { m[fmt.Sprintf("nopAddKey%d", i)] = fmt.Sprintf("%d", i) } } func (m *myMap) growp() { for i := 1; i < 1000000; i++ { (*m)[fmt.Sprintf("pAddKey%d", i)] = fmt.Sprintf("%d", i) } } func fgrow(m myMap) { for i := 1; i < 1000000; i++ { m[fmt.Sprintf("nopAddKey%d", i)] = fmt.Sprintf("%d", i) } } func fgrowp(m *myMap) { for i := 1; i < 1000000; i++ { (*m)[fmt.Sprintf("pAddKey%d", i)] = fmt.Sprintf("%d", i) } } 

Here I have defined two methods and two functions for the growth of the mapa, by value and by pointer. The result of the execution I got this result:
Init method nop: Address = 0xc042054018 Len = 1
Growed method nop: Address = 0xc042054018 Len = 1000000
Init method p: Address = 0xc042054018 Len = 1
Growed method p: Address = 0xc042054018 Len = 1000000
Init func nop: Address = 0xc042054018 Len = 1
Growed func nop: Address = 0xc042054018 Len = 1000000
Init func p: Address = 0xc042054018 Len = 1
Growed func p: Address = 0xc042054018 Len = 1000000


So, we see that the call function maps are changing for the case when they were passed by value, and for the case of passing through the pointer.

Source: https://habr.com/ru/post/329254/


All Articles