Что такое ссылочные (reference) типы в Go и чем они отличаются от значимых (value) типов?

Ответ

В Go все переменные передаются по значению. Однако поведение при передаче зависит от типа данных. Типы в Go можно условно разделить на две категории:

  1. Значимые типы (Value Types):

    При присваивании или передаче в функцию создается полная копия данных. Изменение копии не влияет на оригинал.

    • Примеры: int, float, string, bool, struct, array.
  2. Ссылочные типы (Reference Types):

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

    К ним относятся:

    • Срезы ([]T): Структура, содержащая указатель на массив, длину и ёмкость.
    • Мапы (map[K]V): Указатель на хэш-таблицу.
    • Каналы (chan T): Указатель на внутреннюю структуру канала.
    • *Указатели (`T`)**: Прямой адрес в памяти.
    • Функции (func): Указатель на код функции.
    • Интерфейсы (interface{}): Содержат информацию о типе и указатель на значение.

Пример со срезом демонстрирует это поведение:

func modifySlice(s []int) {
    // s — это копия структуры среза, но она указывает на тот же базовый массив
    s[0] = 100
}

func main() {
    originalSlice := []int{1, 2, 3}
    modifySlice(originalSlice)
    // Изменение видно в оригинальном срезе, так как оба ссылаются на один массив
    fmt.Println(originalSlice) // Вывод: [100 2 3]
}

Ключевое отличие: при работе со ссылочными типами вы манипулируете общими данными через разные переменные, в то время как со значимыми типами вы работаете с независимыми копиями.