Вопрос с собеседования · Go

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

JuniorОсновы языка
Ещё спрашивают так:
  • Всё ли в Go передаётся по значению?
  • Почему изменение структуры в функции не видно снаружи?
Коротко

Всё передаётся по значению — копируется само значение: структура целиком, массив целиком. Чтобы функция изменила объект вызывающего, передают указатель (*T, взять адрес — &x). Срезы, мапы и каналы — маленькие дескрипторы, ссылающиеся на общие данные, поэтому изменения элементов видны снаружи.

  • Нет арифметики указателей (кроме unsafe)
  • Можно вернуть указатель на локальную переменную — компилятор разместит её в куче
  • Большие структуры передают указателем, чтобы не копировать

А ещё append в функции не виден снаружи, если не вернуть новый срез

Попробуйте сами

Срезы Go: len, cap, append и общий массив

Подробно

Копирование значений. Присваивание и передача в функцию копируют значение. Для структуры из десяти полей копируются все десять, для массива [1000]int — тысяча чисел.

Указатель хранит адрес. Через него функция работает с оригиналом. Обращение к полю через указатель пишется так же: u.Name (Go разыменовывает автоматически).

Ссылочные по поведению типы. Срез — структура {указатель на массив, длина, ёмкость}; копия среза указывает на тот же массив, поэтому xs[0] = 1 в функции виден снаружи. Но append, создавший новый массив, меняет только локальную копию дескриптора. Мапа и канал — тоже указатели на внутренние структуры.

Когда указатель: нужно изменить объект; структура большая; нужно различать «нет значения» (nil). Для маленьких неизменяемых значений передача по значению проще и безопаснее.

Пример

type User struct{ Name string }

func rename(u User)     { u.Name = "Петя" }   // меняет копию
func renameP(u *User)   { u.Name = "Петя" }   // меняет оригинал

u := User{Name: "Вася"}
rename(u)    // u.Name == "Вася"
renameP(&u)  // u.Name == "Петя"

Что хотят услышать

  • Передача по значению всегда.
  • Указатели для изменения и больших структур.
  • Почему срезы и мапы ведут себя как ссылки.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Всё передаётся по значению; чтобы менять объект — указатель
  • ✗Структуры передаются по ссылке автоматически, а примитивы — по значению
  • ✗В Go есть арифметика указателей
  • ✗Возвращать указатель на локальную переменную нельзя

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования