Копирование массивов и многомерные массивы
1. Копирование массивов (глубокое копирование)
Основной принцип
В Go присваивание массива создаёт полную копию всех элементов, а не ссылку на исходный массив.
Пример
original := [3]int{1, 2, 3}
copyArr := original // Полная копия всех элементов
copyArr[0] = 999
fmt.Println(original) // [1, 2, 3] — не изменился!
fmt.Println(copyArr) // [999, 2, 3] — изменилась копия
Проверка независимости через адреса
fmt.Printf("&original: %p\n", &original) // 0xc000012078
fmt.Printf("©Arr: %p\n", ©Arr) // 0xc000012090
// Адреса разные → это два разных объекта в памяти
Вывод: Изменение копии не влияет на оригинал — массивы полностью независимы.
2. Многомерные массивы
Определение
Многомерный массив — массив размерности ≥ 2 (двумерные, трёхмерные и т.д.).
Практическое применение
- Двумерные массивы — таблицы, матрицы, игровые поля
- Трёхмерные и выше — редко используются (специфичные задачи: математика, физика, 3D-графика)
3. Двумерные массивы (матрицы)
Синтаксис объявления
// [строки][столбцы]тип
var matrix [4][3]int // 4 строки, 3 столбца
Важно: Порядок размерностей — сначала строки, потом столбцы.
Инициализация
// Способ 1: при объявлении
grid := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
// Способ 2: построчная
grid := [3][2]int{
{1, 2},
{3, 4},
{5, 6},
}
4. Доступ к элементам двумерного массива
Индексация: [строка][столбец]
matrix := [3][2]int{
{1, 2}, // строка 0
{3, 4}, // строка 1
{5, 6}, // строка 2
}
fmt.Println(matrix[0][0]) // 1 — элемент (строка 0, столбец 0)
fmt.Println(matrix[2][0]) // 5 — элемент (строка 2, столбец 0)
fmt.Println(matrix[1][1]) // 4 — элемент (строка 1, столбец 1)
Визуализация индексов
столбец 0 столбец 1
строка 0: [0][0] [0][1]
строка 1: [1][0] [1][1]
строка 2: [2][0] [2][1]
5. Получение размеров двумерного массива
Количество строк
grid := [3][2]int{
{1, 2},
{3, 4},
{5, 6}
}
rows := len(grid) // 3 — количество строк
fmt.Println(rows)
Количество столбцов
cols := len(grid[0]) // 2 — количество элементов в первой строке
fmt.Println(cols)
// grid[1] — это отдельный массив (вторая строка)
fmt.Println(len(grid[1])) // 2
Концепция: Двумерный массив = массив массивов.
6. Перебор двумерного массива (вложенные циклы)
Классический for
grid := [3][2]int{
{1, 2},
{3, 4},
{5, 6},
}
for row := 0; row < len(grid); row++ {
for col := 0; col < len(grid[row]); col++ {
fmt.Printf("grid[%d][%d] = %d\n", row, col, grid[row][col])
}
}
Вывод:
grid[0][0] = 1
grid[0][1] = 2
grid[1][0] = 3
grid[1][1] = 4
grid[2][0] = 5
grid[2][1] = 6
С использованием for range
for rowIndex, row := range grid {
for colIndex, value := range row {
fmt.Printf("[%d][%d] = %d\n", rowIndex, colIndex, value)
}
}
7. Выход за границы в многомерных массивах
Пример ошибок
grid := [3][2]int{
{1, 2},
{3, 4},
{5, 6}
}
// ❌ Нет 4-й строки (индексы 0-2):
// grid[4][1] = 10
// panic: runtime error: index out of range [4] with length 3
// ❌ Нет 3-го столбца (индексы 0-1):
// grid[0][3] = 99
// panic: runtime error: index out of range [3] with length 2
Правило: Проверяйте границы обеих размерностей.
8. Трёхмерные и высокоразмерные массивы
Синтаксис
// [глубина][строки][столбцы]
var cube [2][3][2]int // "Кубик" 2×3×2
Инициализация
cube := [2][3][2]int{
{ // Слой 0
{1, 2},
{3, 4},
{5, 6},
},
{ // Слой 1
{7, 8},
{9, 10},
{11, 12},
},
}
fmt.Println(cube[0][1][1]) // 4
Практическая заметка: Трёхмерные массивы сложны для отладки и редко нужны в реальных задачах.
9. Итоги: Массивы в Go
Ключевые особенности
| Свойство | Описание |
|---|---|
| Размер | Фиксированный, часть типа: [3]int ≠ [5]int |
| Копирование | Глубокое (по значению), не по ссылке |
| Индексация | С 0, для всех размерностей |
| Производительность | Эффективны (размер известен заранее) |
| Ограничения | Нельзя изменить размер после создания |
Преимущества
✅ Известный размер → эффективное выделение памяти
✅ Безопасность: копии независимы
✅ Простота для табличных данных (2D)
Недостатки
❌ Фиксированная длина → нет динамического роста
❌ Копирование может быть дорогим (большие массивы)
❌ Для динамических коллекций нужны срезы (slices)
10. Переход к срезам
Проблема массивов:
arr := [3]int{1, 2, 3}
// Нужно добавить 4-й элемент? Придётся:
// 1. Создать новый массив [4]int
// 2. Скопировать все элементы
// 3. Добавить новый элемент
Решение: Использовать срезы (slices) — динамические обёртки над массивами.
Следующий шаг: Изучение срезов для работы с коллекциями переменного размера.
11. Практические советы
- Для фиксированных данных (дни недели, месяцы) → массивы
- Для динамических коллекций → срезы
- Двумерные структуры → подумайте, нужна ли вам именно матрица или можно обойтись срезом структур
- Всегда тестируйте новые конструкции через
fmt.Println()и эксперименты
Итоговая формула:
Массив = Фиксированный размер + Глубокое копирование + Индексация с 0