ПрограммированиеBackend разработчик

Как устроена работа с неизменяемыми (immutable) и изменяемыми (mutable) структурами данных в Go? Приведите примеры, где это важно учитывать при программировании.

Проходите собеседования с ИИ помощником Hintsage

Ответ

В Go большинство встроенных типов данных (например, int, float, struct) — изменяемые, если они объявлены как переменные, потому что при передаче по значению копируется вся структура или значение. Но есть тонкость: срезы (slice), карты (map), каналы (channel) — ссылочные типы со своей внутренней логикой хранения данных.

Базовые типы:

x := 10 y := x // Здесь создается копия значения, x и y не связаны между собой y = 20 // x останется 10

Срезы:

a := []int{1,2,3} b := a // ссылка на ту же базовую «подложку» массива b[0] = 100 // теперь и a[0] == 100

Это важно, если функция или метод принимает структуру или срез, потому что изменения могут либо затронуть оригинальные данные, либо нет, в зависимости от типа данных и способа передачи (по значению или по ссылке).

Вопрос с подвохом

Вопрос: "Если вы присваиваете один срез другому, получаете ли вы глубокую копию или оба указывают на одни и те же данные?"

Ответ: При простом присваивании срезов (b := a) — оба указывают на один и тот же базовый массив, но имеют независимые длину и ёмкость. Изменение через один из срезов данных самого массива видно в другом.

Пример:

a := []int{1,2,3} b := a b[0] = 42 fmt.Println(a) // [42 2 3]

Чтобы сделать глубокую копию, используют copy:

c := make([]int, len(a)) copy(c, a) c[0] = 99 fmt.Println(a) // [42 2 3], c — независимая копия

История

Сервис фильтрации данных начал возвращать неожиданные результаты: Один разработчик передавал срезы между несколькими функциями без копирования, меняя их состояние. Из-за модификаций слайсов в разных местах логика приложения ломалась, находились странные баги в данных, которые долго не могли отловить.


История

Потеря данных после передачи структуры: В одном проекте при сериализации данных по ошибке удаляли из структуры обязательное поле, потому что объект передавался по ссылке, а не создавалась его копия. В результате из-за этого терялась критичная информация на проде.


История

Ошибка параллельной работы с map: Разработчик скопировал ссылку на map, думая, что изменения не будут влиять на оригинал, как это бывает в других языках. В результате возникла гонка данных при работе в разных горутинах, что привело к падениям приложения.