Golang: Хранение структур в картах
Карты (map
) часто используются для хранения данных, связанных с уникальными ключами. Частый пример — хранение структур (например, пользователей, заказов, товаров), где ключ — это уникальный идентификатор (ID).
Базовый пример
Предположим, у нас есть структура User
:
type User struct {
Name string
Email string
}
Создадим карту, где ключ — целое число (ID), а значение — структура User
:
users := map[int]User{
1: {Name: "Alice", Email: "alice@example.com"},
2: {Name: "Bob", Email: "bob@example.com"},
}
fmt.Println(users[1]) // => {Alice alice@example.com}
Проблема копий
При получении элемента из карты возвращается копия значения, а не ссылка на оригинал:
user := users[1]
user.Name = "Alicia"
fmt.Println(users[1].Name) // => Alice — оригинал не изменился
Чтобы изменить данные в карте, нужно явно присвоить изменённую структуру обратно:
user := users[1]
user.Name = "Alicia"
users[1] = user
fmt.Println(users[1].Name) // => Alicia
Использование указателей
Если нужно часто изменять данные, удобнее хранить в карте указатели на структуры:
users := map[int]*User{
1: {Name: "Alice", Email: "alice@example.com"},
2: {Name: "Bob", Email: "bob@example.com"},
}
users[1].Name = "Alicia"
fmt.Println(users[1].Name) // Alicia — оригинал изменился
В этом случае карта хранит ссылки на объекты, и изменения применяются напрямую.
Перебор карты со структурами
Перебор элементов ничем не отличается от обычных карт:
type User struct {
Name string
Email string
}
users := map[int]*User{
1: {Name: "Alice", Email: "alice@example.com"},
2: {Name: "Bob", Email: "bob@example.com"},
}
for id, user := range users {
fmt.Printf("ID=%d, Name=%s\n", id, user.Name)
}
// => ID=1, Name=Alice
// => ID=2, Name=Bob
Если карта хранит указатели, цикл будет работать аналогично, только user
уже будет указателем.
Задание
Реализуйте функцию UpdateEmail(users map[int]*User, id int, newEmail string) error
, которая обновляет email пользователя с указанным id
в карте users
.
- Если пользователь с таким
id
существует, функция должна изменить егоEmail
наnewEmail
и вернутьnil
. - Если пользователь не найден, функция должна вернуть ошибку с сообщением
"user not found"
.
Пример использования:
users := map[int]*User{
1: {Name: "Alice", Email: "alice@example.com"},
2: {Name: "Bob", Email: "bob@example.com"},
}
err := UpdateEmail(users, 1, "alice@newmail.com")
fmt.Println(users[1].Email) // "alice@newmail.com"
fmt.Println(err) // <nil>
err = UpdateEmail(users, 3, "charlie@mail.com")
fmt.Println(err) // "user not found"
Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Ваше упражнение проверяется по этим тестам
package solution
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUpdateEmail(t *testing.T) {
users := map[int]*User{
1: {Name: "Alice", Email: "alice@example.com"},
2: {Name: "Bob", Email: "bob@example.com"},
}
// Тест успешного обновления
err := UpdateEmail(users, 1, "alice@newmail.com")
assert.NoError(t, err)
assert.Equal(t, "alice@newmail.com", users[1].Email)
// Тест обновления несуществующего пользователя
err = UpdateEmail(users, 3, "charlie@mail.com")
assert.EqualError(t, err, "user not found")
// Проверка, что существующие данные не изменились
assert.Equal(t, "bob@example.com", users[2].Email)
}
Решение учителя откроется через:
20:00
