← Назад к вопросам

Можно ли модифицировать массив?

1.7 Middle🔥 132 комментариев
#Другое

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Краткий ответ

Да, в языке Go массивы можно модифицировать, но с важными особенностями и ограничениями, вытекающими из их природы как значимых типов (value types).

Подробное объяснение

Что такое массив в Go?

В Go массив — это фиксированная последовательность элементов одного типа. Его длина является частью типа данных ([n]T), что отличает массив от среза (slice), который является динамической обёрткой над массивом.

// Объявление массива фиксированной длины 5
var arr [5]int = [5]int{1, 2, 3, 4, 5}

// Массив - значимый тип (хранится в стеке или как часть структуры)
arr2 := arr // Происходит ПОЛНОЕ КОПИРОВАНИЕ всех элементов

Как модифицировать элементы массива?

Вы можете изменять отдельные элементы по индексу, используя синтаксис квадратных скобок:

package main

import "fmt"

func main() {
    // Создаём массив
    numbers := [3]int{10, 20, 30}
    
    // Модифицируем элементы
    numbers[0] = 100  // Первый элемент теперь 100
    numbers[1] *= 2   // Второй элемент умножаем на 2 → 40
    numbers[2]++      // Третий элемент увеличиваем на 1 → 31
    
    fmt.Println(numbers) // [100 40 31]
    
    // Модификация через цикл
    for i := 0; i < len(numbers); i++ {
        numbers[i] += 5
    }
    fmt.Println(numbers) // [105 45 36]
}

Ключевые особенности модификации массивов

1. Значимый тип (Value Semantics)

При передаче массива в функцию или присваивании другой переменной происходит полное копирование всех элементов:

func modifyArray(arr [3]int) {
    arr[0] = 999 // Модифицируется только локальная копия
    fmt.Println("Inside function:", arr) // [999 2 3]
}

func main() {
    original := [3]int{1, 2, 3}
    modifyArray(original)
    fmt.Println("Outside function:", original) // [1 2 3] - НЕ изменился!
}

2. Работа через указатели для избежания копирования

Чтобы модифицировать массив внутри функции без создания копии, используйте указатели:

func modifyArrayViaPointer(arr *[3]int) {
    arr[0] = 999 // Синтаксис разыменования автоматический
    // Эквивалентно: (*arr)[0] = 999
}

func main() {
    original := [3]int{1, 2, 3}
    modifyArrayViaPointer(&original)
    fmt.Println(original) // [999 2 3] - успешно изменён!
}

3. Различия между массивом и срезом

Важно понимать разницу, так как новички часто их путают:

// МАССИВ - фиксированная длина, передаётся по значению (копируется)
arr := [3]int{1, 2, 3}
arrCopy := arr // КОПИРОВАНИЕ всех элементов

// СРЕЗ - динамическая длина, передаётся ссылка на базовый массив
slice := []int{1, 2, 3}
sliceRef := slice // Копируется только дескриптор (заголовок среза)
sliceRef[0] = 999 // Изменяет ОРИГИНАЛЬНЫЕ данные
fmt.Println(slice[0]) // 999 - тоже изменился!

Практические рекомендации

  1. Когда использовать массивы:

    • Когда размер коллекции фиксирован и известен на этапе компиляции
    • Для работы с криптографическими хешами ([32]byte)
    • В высокопроизводительных сценариях, где нужно избежать накладных расходов на выделение памяти
    • Как базовый буфер для срезов
  2. Типичный паттерн модификации:

func processBuffer(buf *[4096]byte) {
    for i := range buf {
        buf[i] = byte(i % 256) // Модификация через указатель
    }
}

func main() {
    var buffer [4096]byte
    processBuffer(&buffer) // Эффективно, без копирования
}
  1. Модификация многомерных массивов:
matrix := [2][3]int{{1, 2, 3}, {4, 5, 6}}
matrix[0][1] = 99 // Изменяем элемент
matrix[1] = [3]int{7, 8, 9} // Заменяем целую строку

Ограничения

  • Нельзя изменить размер массива после создания
  • Нельзя использовать append() с массивами (только со срезами)
  • Сравнение массивов возможно только если они одинакового типа [n]T

Заключение

Массивы в Go поддаются модификации на уровне элементов, но их поведение при передаче между функциями отличается от привычных ссылочных типов в других языках. Понимание семантики значений (value semantics) критически важно для корректной работы с массивами. В большинстве практических случаев разработчики предпочитают использовать срезы, которые предоставляют больше гибкости, но в оптимизированном коде или при работе с фиксированными структурами данных массивы остаются важным инструментом.