Тип map всегда передается по ссылке

от автора

Недавно проскакивала статья о том, как устроены разные простые типы и слайсы в памяти. Из этой статьи мы узнали, почему переданный «по значению» слайс в функцию является передачей слайса по ссылке только до того момента, пока слайс внутри функции не потребует реаллокацию в памяти при увеличении своего capacity. Если внутри функции capacity этого слайса изменяется, и он был передан «по значению», а не в виде указателя, то слайс начинает ссылаться на совсем другой массив, совсем не тот, который будет дальше использоваться в вызывающей функции.
Такая особенность слайса может порождать «случайные» ошибки логики работы программы на этапе выполнения, если программист не учел это.
У меня возник вопрос, а нет ли похожей ситуации с типом map? Ведь у него тоже есть capacity, и он тоже может менять аллокацию в памяти при росте числа пар значений.

И я провел небольшой эксперимент, написав такой код:

package main  import ( 	"fmt" )  type myMap map[string]string  func main() {  	mymap := make(myMap, 1) 	mymap["firstKey"] = "firstValue" 	fmt.Printf("Init nop: Address = %p Len = %d\n", &mymap, len(mymap)) 	mymap.grow() 	fmt.Printf("Growed nop: Address = %p Len = %d\n", &mymap, len(mymap))  	mymap = make(myMap, 1) 	mymap["firstKey"] = "firstValue" 	fmt.Printf("Init p: Address = %p Len = %d\n", &mymap, len(mymap)) 	(&mymap).growp() 	fmt.Printf("Growed 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) 	} } 

Здесь я определил два метода роста мапы, один по значению, а второй по указателю.
Результатом выполнения я получил такой результат:

Init nop: Address = 0xc042054018 Len = 1
Growed nop: Address = 0xc042054018 Len = 1000000
Init p: Address = 0xc042054018 Len = 1
Growed p: Address = 0xc042054018 Len = 1000000

Итак, мы видим, что мапы вызывающей функции меняются и для случая, когда они были переданы по значению, и для случая передачи через указатель.
Отсюда сделаем важный вывод: везде и всегда мапы передаются по ссылке, будь то выражение присваивания или передача параметром в функцию. Рост размера мапы внутри функции оказывает влияние на мапу, используемую в вызывающей функции, т.к. в памяти всегда остается одна и та же структура данных.
ссылка на оригинал статьи https://habrahabr.ru/post/329254/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *