Многомерные срезы
1. Срез срезов: [][]T
Определение
Многомерный срез — это срез, где каждый элемент сам является срезом.
var matrix [][]int // Срез срезов int
Отличие от массива:
arr := [3][4]int{} // Массив: фиксированные размеры 3×4
slice := [][]int{} // Срез: переменное количество строк и столбцов
2. Ключевая особенность: разная длина строк
В массивах
arr := [3][4]int{
{1, 2, 3, 4},
{5, 6, 7, 8}, // Все строки ОБЯЗАНЫ иметь 4 элемента
{9, 10, 11, 12},
}
В срезах срезов (зубчатый массив)
matrix := [][]int{
{1, 2, 3}, // 3 элемента
{4, 5}, // 2 элемента
{6, 7, 8, 9}, // 4 элемента — разная длина!
}
Каждая строка — независимый срез с собственной длиной.
3. Создание многомерных срезов
Способ 1: Литерал
matrix := [][]int{
{1, 2, 3},
{4, 5},
{6, 7, 8, 9},
}
fmt.Println(matrix)
// [[1 2 3] [4 5] [6 7 8 9]]
Способ 2: Через make() (фиксированные размеры)
// Создаём срез из 3 строк
matrix := make([][]int, 3)
// Инициализируем каждую строку
matrix[0] = []int{1, 2, 3}
matrix[1] = []int{4, 5}
matrix[2] = []int{6, 7, 8, 9}
Способ 3: Динамическое добавление строк
var matrix [][]int
matrix = append(matrix, []int{1, 2, 3})
matrix = append(matrix, []int{4, 5})
matrix = append(matrix, []int{6, 7, 8, 9})
fmt.Println(matrix)
// [[1 2 3] [4 5] [6 7 8 9]]
Строки добавляются динамически.
4. Доступ к элементам
matrix := [][]int{
{1, 2, 3},
{4, 5},
{6, 7, 8, 9},
}
// Обращение: matrix[строка][столбец]
fmt.Println(matrix[0][1]) // 2
fmt.Println(matrix[2][3]) // 9
Индексация:
matrix[0][1] → строка 0, элемент 1 → 2
matrix[2][3] → строка 2, элемент 3 → 9
5. Перебор многомерных срезов
for range по строкам
matrix := [][]int{
{1, 2, 3},
{4, 5},
{6, 7, 8, 9},
}
for i, row := range matrix {
fmt.Printf("Строка %d: %v\n", i, row)
}
Вывод:
Строка 0: [1 2 3]
Строка 1: [4 5]
Строка 2: [6 7 8 9]
Вложенный for range по всем элементам
for i, row := range matrix {
for j, value := range row {
fmt.Printf("matrix[%d][%d] = %d\n", i, j, value)
}
}
Вывод:
matrix[0][0] = 1
matrix[0][1] = 2
matrix[0][2] = 3
matrix[1][0] = 4
matrix[1][1] = 5
matrix[2][0] = 6
matrix[2][1] = 7
matrix[2][2] = 8
matrix[2][3] = 9
6. Зубчатые массивы (Jagged Arrays)
Название в других языках:
- C#, Java: Jagged Array (зубчатый массив)
- Python: Список списков (
list[list[int]])
// Go: срез срезов
jagged := [][]int{
{1, 2},
{3, 4, 5, 6},
{7},
}
Аналог в C#:
int[][] jagged = new int[][] {
new int[] {1, 2},
new int[] {3, 4, 5, 6},
new int[] {7}
};
Аналог в Python:
jagged = [
[1, 2],
[3, 4, 5, 6],
[7]
]
7. Отличие от прямоугольных массивов
| Тип | Пример Go | Форма | Ограничения |
|---|---|---|---|
| Прямоугольный массив | [3][4]int |
Фиксированная 3×4 | Все строки одной длины |
| Зубчатый срез | [][]int |
Переменная | Каждая строка — разная длина |
8. Типичные задачи
Треугольная матрица
triangle := [][]int{
{1},
{2, 3},
{4, 5, 6},
{7, 8, 9, 10},
}
for i, row := range triangle {
fmt.Printf("Уровень %d: %v\n", i, row)
}
Вывод:
Уровень 0: [1]
Уровень 1: [2 3]
Уровень 2: [4 5 6]
Уровень 3: [7 8 9 10]
Создание прямоугольной матрицы через срезы
rows, cols := 3, 4
matrix := make([][]int, rows)
for i := range matrix {
matrix[i] = make([]int, cols)
}
// Заполнение
matrix[0][0] = 1
matrix[1][2] = 5
matrix[2][3] = 9
fmt.Println(matrix)
// [[1 0 0 0] [0 0 5 0] [0 0 0 9]]
9. Когда использовать
Применимо:
- Данные с переменным количеством элементов в строках
- Графы (списки смежности)
- Треугольные/разреженные матрицы
- Иерархические структуры
Не применимо (лучше использовать [N][M]int):
- Матрицы фиксированного размера
- Изображения (пиксели)
- Математические операции над матрицами
10. Специфика хранения в памяти
Массив [3][4]int:
Непрерывный блок: [1][2][3][4][5][6][7][8][9][10][11][12]
Срез срезов [][]int:
Внешний срез: [ptr1, ptr2, ptr3]
↓ ↓ ↓
Строки: [1,2,3] [4,5] [6,7,8,9]
(3 отдельных блока памяти)
Вывод: Срезы срезов — это не непрерывный блок памяти.
11. Итоги
✅ [][]T — срез срезов, не фиксированная структура
✅ Каждая строка может иметь разную длину
✅ Аналог зубчатых массивов (C#/Java) и списков списков (Python)
✅ Создание: литерал, make(), или динамически через append
✅ Доступ: matrix[row][col]
✅ Перебор: вложенный for range
✅ Не часто используется в практике
Ключевое отличие:
[3][4]int → прямоугольная матрица, фиксированная
[][]int → зубчатый массив, переменные размеры