Многомерные срезы


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    → зубчатый массив, переменные размеры