Ответ
В Go все без исключения аргументы передаются в функцию по значению (pass-by-value). Это означает, что функция всегда получает копию передаваемой переменной.
Однако поведение при изменении аргумента внутри функции зависит от его типа.
1. Простые типы и структуры
Для типов, таких как int
, float
, string
, bool
, а также для структур и массивов, создается полная копия значения. Изменения копии внутри функции не влияют на оригинальную переменную.
2. Указатели
Когда вы передаете указатель, копируется сам указатель (адрес в памяти), а не данные, на которые он указывает. Так как и оригинал, и копия указывают на одну и ту же область памяти, изменения данных по этому адресу будут видны снаружи.
3. Слайсы, мапы и каналы
Это самая частая область недопонимания. Слайсы, мапы и каналы являются ссылочными типами. Внутренне они реализованы как структуры, содержащие указатель на базовую структуру данных.
Когда вы передаете такой тип в функцию, вы по-прежнему передаете копию, но это копия дескриптора (заголовка), а не всех данных.
- Слайс: Копируется структура, содержащая указатель на нижележащий массив, длину (
len
) и ёмкость (cap
). - Мапа: Копируется указатель на структуру, управляющую хэш-таблицей.
- Канал: Копируется указатель на внутреннюю структуру канала.
Поскольку копия дескриптора содержит указатель на ту же самую базовую структуру данных, изменение элементов слайса или мапы внутри функции будет видно снаружи.
Важный нюанс: Если внутри функции вы измените сам дескриптор слайса (например, через append
, который может создать новый нижележащий массив), эти изменения не будут видны снаружи, так как вы меняете копию дескриптора.