Как в Go передаются аргументы в функции: по значению или по ссылке?

Ответ

В Go все без исключения аргументы передаются в функцию по значению (pass-by-value). Это означает, что функция всегда получает копию передаваемой переменной.

Однако поведение при изменении аргумента внутри функции зависит от его типа.

1. Простые типы и структуры

Для типов, таких как int, float, string, bool, а также для структур и массивов, создается полная копия значения. Изменения копии внутри функции не влияют на оригинальную переменную.

2. Указатели

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

3. Слайсы, мапы и каналы

Это самая частая область недопонимания. Слайсы, мапы и каналы являются ссылочными типами. Внутренне они реализованы как структуры, содержащие указатель на базовую структуру данных.

Когда вы передаете такой тип в функцию, вы по-прежнему передаете копию, но это копия дескриптора (заголовка), а не всех данных.

  • Слайс: Копируется структура, содержащая указатель на нижележащий массив, длину (len) и ёмкость (cap).
  • Мапа: Копируется указатель на структуру, управляющую хэш-таблицей.
  • Канал: Копируется указатель на внутреннюю структуру канала.

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

Важный нюанс: Если внутри функции вы измените сам дескриптор слайса (например, через append, который может создать новый нижележащий массив), эти изменения не будут видны снаружи, так как вы меняете копию дескриптора.