Доступ к полям структуры в значении карты (без копирования)
Проблема с доступом к полям структуры в мапе Go
Предположим, что у нас есть следующий код:
type User struct {
name string
}
users := make(map[int]User)
users[5] = User{"Steve"}
Я столкнулся с проблемой доступа к полю name
у экземпляра структуры, который сейчас хранится в мапе. Когда я пытаюсь выполнить следующий код:
users[5].name = "Mark"
Я получаю ошибку: cannot assign to users[5].name
.
Может кто-то объяснить, почему это не сработало? Как я могу корректно получить доступ к структуре, сохраненной в мапе, или какая логика стоит за тем, что это невозможно?
Примечания
Я знаю, что можно изменить это поле, сделав копию структуры, изменив копию, а затем скопировав обратно в мапу — но это дорогостоящая операция копирования.
Также я в курсе, что можно использовать указатели на структуры в мапе, но мне не хочется делать это.
2 ответ(ов)
Основная проблема заключается в том, что нельзя получить адрес элемента внутри карты. Вы могли бы подумать, что компилятор преобразует users[5].name = "Mark"
в следующее
(&users[5]).name = "Mark"
Однако это не компилируется и выдает ошибку
cannot take the address of users[5]
Это позволяет картам использовать свою свободу для реорганизации элементов по своему усмотрению для эффективного использования памяти.
Единственный способ явно изменить что-то в карте — это присвоить значение, т.е.
t := users[5]
t.name = "Mark"
users[5] = t
Таким образом, вам придется либо смириться с копированием выше, либо использовать указатели в вашей карте. Хранение указателей имеет недостаток в том, что оно требует больше памяти и больше выделений памяти, что может перевесить преимущества копирования, — это уже зависит от вас и вашего приложения.
Третий вариант — использовать срез. Ваша исходная запись будет работать идеально, если вы измените users := make(map[int]User)
на users := make([]User, 10)
.
Карты обычно представляют собой разреженные хеш-таблицы, которые перераспределяются, когда превышается заданный порог. Перераспределение может вызвать проблемы, если кто-то удерживает указатели на значения в этих таблицах.
Если вы стремитесь избежать создания копии объекта, вы можете хранить указатель на сам объект в качестве значения.
Когда мы обращаемся к элементу карты, возвращаемое значение передается "по значению", если использовать терминологию, применяемую к параметрам функции. Таким образом, редактирование возвращенной структуры не влияет на содержимое карты.
Существует ли цикл foreach в Go?
Как сопоставить любой символ на нескольких строках в регулярном выражении?
Отформатировать строку в Go без вывода?
Есть ли способ получить доступ к приватным полям структуры из другого пакета?
Получение тега поля структуры с использованием пакета reflect в Go