Ответ Себастьяна точен, но я хотел знать, почему это безопасно, поэтому я немного покопался в исходном коде карты . Похоже, что при вызове delete(k, v)он просто устанавливает флаг (а также меняет значение счетчика) вместо фактического удаления значения:
b->tophash[i] = Empty;
(Пусто - это константа для значения 0)
На самом деле карта, по-видимому, выделяет определенное количество сегментов в зависимости от размера карты, который увеличивается по мере выполнения вставок со скоростью 2^B(из этого исходного кода ):
byte *buckets; // array of 2^B Buckets. may be nil if count==0.
Таким образом, почти всегда выделяется больше сегментов, чем вы используете, и когда вы выполняете rangeпереход по карте, он проверяет это tophashзначение каждого сегмента в нем, 2^Bчтобы увидеть, может ли он пропустить его.
Подводя итог, можно сказать, что deleteвнутри a rangeбезопасно, потому что данные технически все еще там, но когда он проверяет, tophashон видит, что может просто пропустить их и не включать в любую rangeоперацию, которую вы выполняете. Исходный код даже включает TODO:
// TODO: consolidate buckets if they are mostly empty
// can only consolidate if there are no live iterators at this size.
Это объясняет, почему использование delete(k,v)функции на самом деле не освобождает память, а просто удаляет ее из списка сегментов, к которым вам разрешен доступ. Если вы хотите освободить реальную память, вам нужно сделать всю карту недоступной, чтобы вмешалась сборка мусора. Вы можете сделать это, используя строку вида
map = nil