В реальных программах редко обрабатывается одна сущность. Обычно приходится работать с множеством: список заказов, множество пользователей, каталог товаров. Чтобы хранить и организовывать такие данные, в Go есть срезы и карты. А если их элементами становятся структуры, мы получаем естественные и удобные модели.
Срезы
Срез — это упорядоченный список элементов. Он удобен, когда важен порядок или нужно пройтись по всем объектам.
Начнем с простого: список имен пользователей.
users := []string{"Анна", "Борис", "Светлана"}
for i, name := range users {
fmt.Println(i, name)
}
Здесь []string
— это срез строк. Мы видим порядок, можем обратиться к элементу по индексу (users[0]
даст "Анна") и пройтись по всем в цикле.
Карты
Карта — это набор пар «ключ → значение». Мы используем ее, когда порядок не важен, а быстрый доступ по ключу критичен.
Простейший пример: справочник паролей по логину.
passwords := map[string]string{
"admin": "qwerty123",
"user": "12345",
}
fmt.Println(passwords["admin"]) // выведет qwerty123
Здесь map[string]string
— это карта, где ключом выступает логин, а значением — пароль. Доступ по ключу мгновенный, перебор не нужен.
Срезы структур
Теперь усложним задачу. Представим систему заказов и определим структуру Order
:
type Order struct {
ID int
Customer string
Items []string
Status string
}
Создадим срез заказов:
orders := []Order{
{ID: 101, Customer: "Иван", Items: []string{"Ноутбук", "Мышь"}, Status: "new"},
{ID: 102, Customer: "Мария", Items: []string{"Телефон"}, Status: "processing"},
}
for _, order := range orders {
fmt.Printf("Заказ %d для %s, статус: %s\n", order.ID, order.Customer, order.Status)
}
Все данные собраны в единую модель, нет риска рассинхронизации между отдельными срезами.
Карты со структурами
Чтобы быстро находить заказ по ID, используем карту:
ordersMap := map[int]Order{
101: {ID: 101, Customer: "Иван", Items: []string{"Ноутбук", "Мышь"}, Status: "new"},
102: {ID: 102, Customer: "Мария", Items: []string{"Телефон"}, Status: "processing"},
}
order := ordersMap[101]
fmt.Println(order.Customer) // Иван
Карта позволяет получать заказ напрямую, без перебора.
Структуры как ключи карт
Иногда сама структура может быть ключом. Например, оценки студентов по имени и возрасту:
type Student struct {
Name string
Age int
}
grades := map[Student]float64{
{Name: "Ольга", Age: 20}: 4.5,
{Name: "Петр", Age: 22}: 3.9,
}
Важно: ключ не может содержать несравнимые типы — такие как срезы или карты.
Комбинации
На практике часто встречаются вложенные варианты:
- срез внутри структуры, которая хранится в карте;
- карта внутри структуры, которая лежит в срезе;
- карта, где значением является срез структур;
- срез структур, внутри которых есть срезы.
Когда использовать
- Срез — когда нужен порядок и обход всех элементов.
- Карта — когда важен быстрый доступ по ключу и порядок не имеет значения.
На практике оба механизма комбинируются: срез для отображения и сортировки, карта для поиска и проверки существования.
И только когда мы соединяем структуры со срезами и картами, мы получаем мощные и гибкие модели данных. Например, список всех заказов (срез структур) или база клиентов, где каждому email соответствует карточка клиента (карта структур).
Самостоятельная работа
Небольшое задание на работу со структурами и срезами.
Задачи:
Воспользуйтесь структурой
Book
:type Book struct { Title string Author string }
Создайте срез из не менее чем трёх книг.
Выведите заголовки всех книг в одной строке, через запятую.
Отфильтруйте книги по автору (например, "Иванов") и выведите количество таких книг.
Показать пример ответа
package main
import (
"fmt"
"strings"
)
type Book struct {
Title string
Author string
}
func main() {
// 2) Срез структур
books := []Book{
{Title: "Go для начинающих", Author: "Иванов"},
{Title: "Алгоритмы", Author: "Петров"},
{Title: "Советы по Go", Author: "Иванов"},
}
// 3) Заголовки через запятую
titles := make([]string, 0, len(books))
for _, b := range books {
titles = append(titles, b.Title)
}
fmt.Println(strings.Join(titles, ", "))
// 4) Фильтрация по автору
author := "Иванов"
count := 0
for _, b := range books {
if b.Author == author {
count++
}
}
fmt.Printf("Книг автора %s: %d\n", author, count)
}
Дополнительные материалы
- Go Blog — Slices: usage and internals
- Effective Go — Slices
- Effective Go — Maps
- Go Spec — Slice types
- Go Spec — Map types
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.