Search
Write a publication
Pull to refresh

Comments 7

иногда хочется сделать ключом два значения, но не хочется объявлять дополнительно структуры. для этого может оказаться полезным в качестве ключа указать массив. например:

m := map[[2]any]string{}

m[[2]any{"user", 111}] = "Alice"
m[[2]any{"user", 222}] = "Bob"

println(m[[2]any{"user", 222}])

а если еще добавить в качестве мини-утилиты функцию

func key2(a, b any) [2]any {
	return [2]any{a, b}
}

то можно писать так: m[key2("user", 111)] = "Alice"

иногда бывает полезным.

а то частенько встречал код, где делают мапы мапов %)


и тут я замечаю кое-что интересное :) не думал что ключом может быть массив из any - т.к. any ведь может быть и не сравнимым типом. попробовал заменить 222 на слайс - обламывается в рантайме. т.е. он не только при компиляции проверяет что ключ валидного типа. любопытно, спасибо!

а насчет ключа из двух значений - в скриптовых языках я обычно объединяю два значения в строчку чтобы сделать ключ - например, часто когда ключом надо координату сделать:

m[x .. ":" .. y] = 100

Про порядок ключей и печать мапы - можно уточнить, пакет fmt сам сортирует мапу по ключу при формировании mapString, поэтому обычный fmt.Print(m) всегда будет печатать "отсортированную" мапу. Видел подобный вопрос на каком-то из моков, возможно кому-то пригодится)

да, спасибо, подписал под примером а то действительно выглядит неясно зачем он там :)

Добрый день! Вы так интересно описываете. Хотелось бы видеть у вас больше статей про Go.

"В каком порядке range перебирает элементы мэпы?" и подобные вопросы.

Это не специфицировано. Другими словами "об этом не нужно думать или спрашивать". Спецификация языка упоминает в параграфе про мэпы:

A map is an unordered group of elements... (Мэпа - неупорядоченный набор элементов...)

и про range

The iteration order over maps is not specified and is not guaranteed to be the same (порядок итерирования по мэпам не определен и нет гарантии что он будет всегда одинаков...)

Немного дополню информацией из второго издания книги "Go идиомы и паттерны проектирования" Джона Боднера:

При обходе мапы с помощью цикла for-range, порядок элементов будет меняться, иногда повторяясь. То есть три запуска for-range для одной и той же мапы обойдут элементы в разном порядке.

Такое поведение обусловлено соображениями безопасности. В более ранних версиях Go порядок обхода ключей у отображений с одинаковыми элементами обычно (но не всегда) был одинаковым. Это порождало две проблемы:

  1. Разработчики писали код с расчетом на фиксированный порядок обхода, но он иногда приводил к сбоям в самых неподходящий момент.

  2. Если отображение всегда хеширует элементы в одни и те же значения и злоумышленнику известно, что сервер сохраняет пользовательские данные в виде отображения, то можно добиться реального замедления работы сервера с помощью DdoS-атаки на основе хеш-коллизий (Hash DoS), отправив серверу специально подготовленные данные, все ключи которых хешируются в одно и то же ведро (что за ведро?)

Чтобы устранить обе эти проблемы, разработчики языка Go внесли два изменения в реализацию отображения. Во-первых, они модифицировали хеш-алгоритм для отображений таким образом, чтобы при каждом создании переменной отображения генерировалось случайное число. Во-вторых, они сделали так, чтобы при каждом обходе отображения с помощью for-range порядок обхода элементов немного варьировался. Эти два изменения существенно усложнили проведение DoS-атаки на основе хеш-коллизий.

Из этого правила есть одно исключение: чтобы упростить процесс отладки, функции форматирования, такие как fmt.Println, всегда выводят отображения в порядке возрастания ключей.

Sign up to leave a comment.

Articles