> Какие типы данных относятся к мутабельным, а какие к немутируемым (Go)

Уровень: senior · Роль: backend · Категория: Технические вопросы

Компании: Астра

Стек: Go

> Пример ответа

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

В Go мутабельность определяется передачей по ссылке или по значению. Мутабельные типы: slice, map, channel, pointer, function, interface (если динамический тип мутабельный). Иммутабельные: все value-типы - int, float, string, bool, array, struct (если все поля - value-типы). String технически иммутабелен, но при присваивании создаётся новая копия. Важно: мутабельность в Go - это свойство ссылочных типов данных, а не синтаксиса.

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

В Go нет строгого разделения на mutable/immutable, как в Java или Python. Вместо этого есть ссылочные типы (reference types) и типы-значения (value types).

Мутабельные (ссылочные) типы:

  • slice - ссылка на массив, можно менять элементы через индекс, append может перераспределить память
  • map - хеш-таблица, можно добавлять/удалять ключи
  • channel - можно отправлять и принимать значения
  • pointer - можно разыменовать и изменить значение по адресу
  • function - можно вызывать, но сама функция неизменяема, мутабельность через замыкания
  • interface - хранит указатель на данные, мутабельность зависит от динамического типа

Иммутабельные (value) типы:

  • int, int8, int16, int32, int64 - целые числа
  • uint, uint8, uint16, uint32, uint64 - беззнаковые
  • float32, float64 - числа с плавающей точкой
  • complex64, complex128 - комплексные
  • bool - логический
  • string - строка, иммутабельна по спецификации
  • array - массив фиксированной длины, передаётся по значению
  • struct - структура, передаётся по значению, если не содержит ссылочных полей

Ключевой момент: при передаче value-типа в функцию создаётся копия. Изменения внутри функции не влияют на оригинал. При передаче ссылочного типа копируется только заголовок (slice header, map header), но данные общие.

String - особый случай: строка иммутабельна, но при конкатенации создаётся новая строка. Однако байты строки нельзя изменить по индексу - это приведёт к compile error.

На практике

На практике мутабельность влияет на:

  • Проектирование API - если функция должна изменить данные, передавайте указатель или slice; если нет - передавайте value
  • Гонки данных - мутабельные типы требуют синхронизации при конкурентном доступе
  • Производительность - копирование больших struct дорого, но передача ссылок может привести к неожиданным изменениям
  • Чистоту кода - иммутабельные данные проще тестировать и отлаживать

Распространённый паттерн: возвращать копию slice, а не оригинал, чтобы защитить внутреннее состояние.

Пример кода

GO
package main
import "fmt"
type User struct {
Name string
Age int
}
func mutateSlice(s []int) {
s[0] = 100 // изменит оригинал
}
func mutateMap(m map[string]int) {
m["key"] = 42 // изменит оригинал
}
func mutateStruct(u User) {
u.Name = "Changed" // не изменит оригинал
}
func mutateStructPtr(u *User) {
u.Name = "Changed" // изменит оригинал
}
func main() {
// slice - мутабельный
nums := []int{1, 2, 3}
mutateSlice(nums)
fmt.Println(nums) // [100 2 3]
// map - мутабельный
dict := map[string]int{"key": 0}
mutateMap(dict)
fmt.Println(dict) // map[key:42]
// struct - иммутабельный при передаче по значению
user := User{Name: "Alice", Age: 30}
mutateStruct(user)
fmt.Println(user.Name) // Alice
// struct - мутабельный через указатель
mutateStructPtr(&user)
fmt.Println(user.Name) // Changed
// string - иммутабельный
str := "hello"
// str[0] = 'H' // compile error
str = "Hello" // создаётся новая строка
}

Как отвечать на собеседовании

Начните с чёткого разделения: ссылочные типы мутабельны, value-типы иммутабельны. Приведите примеры из каждого класса. Упомяните нюанс со string - иммутабельна, но это не значит, что переменную нельзя переназначить. Покажите понимание передачи по значению и по ссылке на примере slice header и struct. Если спросят про производительность - скажите, что копирование value-типов дёшево для маленьких данных, но для больших структур лучше использовать указатели. Упомяните, что в Go нет встроенных иммутабельных коллекций, но можно реализовать через интерфейсы.

Что проверяет интервьюер

Интервьюер проверяет:

  • Понимание модели памяти Go
  • Различие между ссылочными и value-типами
  • Знание поведения slice и map при передаче в функции
  • Понимание последствий мутабельности для конкурентности
  • Умение объяснить trade-off между копированием и ссылками
  • Глубину понимания string как иммутабельного типа

Типичные ошибки

  • Утверждение, что string мутабельна, потому что её можно переназначить - это разные вещи
  • Путаница между array и slice: array - value-тип, slice - ссылочный
  • Непонимание, что struct с полем slice становится частично мутабельной
  • Утверждение, что все типы в Go передаются по значению - это верно для заголовков, но данные общие
  • Игнорирование того, что map и slice при передаче в функцию могут быть изменены, но сам заголовок копируется
  • Смешивание понятий "мутабельность" и "изменяемость переменной" - переменную можно переназначить всегда, но это не делает тип мутабельным

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью