сеньорчикОткрыть в Telegram
← все вопросывопросы для собеседований · Интерфейсы и основы Go

Вопросы по интерфейсам и основам Go на собеседовании

Основы Go спрашивают через ловушки: интерфейс, который не равен nil, слайс, неожиданно поделивший массив с другим, и мапа, которая паникует при параллельной записи. Именно эти места отделяют читавших книгу от писавших код.

82 вопросов в банке·10 подтем·ниже разбор 9

Из чего состоит тема

Так тема разложена в тренажёре: движок ведёт прогресс по каждой подтеме отдельно и возвращает те, где вы ошибаетесь.

Разборы подтем

Конспект по каждой: что это, как отвечать вслух, на чём валятся, плюс вопросы для самопроверки.

Примеры вопросов с разбором

  1. #go_maps_strings1 / 9
    var m map[string]int (без make). Что делают чтение m["x"] и запись m["x"]=1?
    A)Чтение вернёт 0; запись паникует: assignment to entry in nil map
    B)Оба паникуют: nil-мапа непригодна ни к чему
    C)Чтение вызовет панику, а запись молча создаст мапу автоматически
    D)Оба работают: nil-мапа ведёт себя как пустая
    показать ответ и разбор
    +A)Чтение вернёт 0; запись паникует: assignment to entry in nil map

    // разбор: nil-мапа читается как пустая — любой ключ даёт нулевое значение (и comma-ok даёт ok=false), но запись в неё паникует «assignment to entry in nil map», потому что вставке некуда идти. Поэтому мапу перед записью создают через make или литерал. Частый баг — забыть make у мапы-поля структуры. Спот-чек: чтение дало 0.

  2. #go_pointers2 / 9
    Что верно про указатели в Go?
    A)Есть арифметика указателей как в C: p+1 сдвигает на элемент
    B)&x берёт адрес, *p разыменовывает; арифметики указателей нет
    C)Указатели запрещены — Go передаёт всё по ссылке автоматически
    D)new(T) возвращает T по значению, а не *T
    показать ответ и разбор
    +B)&x берёт адрес, *p разыменовывает; арифметики указателей нет

    // разбор: &x даёт адрес, *p разыменовывает, new(T) выделяет обнулённый T и возвращает *T. Но адресной арифметики (p+1) в Go нет — это часть безопасности памяти (обход только через пакет unsafe). Указатели существуют и нужны: мутация, крупные структуры, опциональность через nil — просто без арифметики адресов.

  3. #go_slices3 / 9
    b := a[:2] от слайса a с запасом cap, затем b = append(b, x). Что со слайсом a?
    A)a не изменится: append тут неизменно создаёт отдельный новый массив
    B)Компилятор запретит append к под-слайсу другого слайса
    C)При запасе ёмкости append пишет в общий массив и затирает a[2]
    D)a обрежется до длины b автоматически
    показать ответ и разбор
    +C)При запасе ёмкости append пишет в общий массив и затирает a[2]

    // разбор: Под-слайс делит с исходным один backing-массив. Если у него есть запас (cap > len), append пишет в тот же массив по месту — и портит элементы исходного за его длиной (a[2]). Если запаса нет, append выделяет новый массив и связь рвётся. Отсюда коварные баги: поведение append зависит от cap. Спот-чек: a стал [1 2 99].

  4. #go_structs_methods4 / 9
    Структуры с полями-числами. Что даёт T{1,2} == T{1,2}?
    A)true — структуры сравнимы поэлементно, если поля сравнимы
    B)false — оператор сравнивает адреса, а они разные
    C)Ошибка компиляции: структуры оператором == не сравнивают
    D)true, но только для структур, помеченных как comparable
    показать ответ и разбор
    +A)true — структуры сравнимы поэлементно, если поля сравнимы

    // разбор: == для структур сравнивает их поэлементно и даёт true, если равны все соответствующие поля — при условии, что все поля СРАВНИМЫ. Структура со слайсом/мапой/функцией внутри уже несравнима: == не скомпилируется. Сравниваются значения полей, а не адреса. Присваивание структуры тоже копирует её целиком по значению. Спот-чек: true.

  5. #go_types_zero5 / 9
    Чему равны var n int; var s string; var p *int сразу после объявления?
    A)0, "" и nil соответственно — это нулевые значения типов
    B)Неинициализированному мусору из памяти, как в C
    C)Это ошибка компиляции: переменную надо инициализировать явно
    D)0, "" и указателю на нулевой int с валидным адресом
    показать ответ и разбор
    +A)0, "" и nil соответственно — это нулевые значения типов

    // разбор: В Go нет неинициализированных переменных: объявленная без значения получает нулевое значение типа — 0 у чисел, "" у строк, false у bool, nil у указателей/слайсов/мап/каналов/интерфейсов/функций. Это детерминированно (не мусор из памяти) и часто делает тип полезным из коробки: var b bytes.Buffer уже готов к работе.

  6. #go_any_assert6 / 9
    Что такое any в современном Go и как достать из него конкретный тип?
    A)any — это указатель void*, тип достают приведением (T)x
    B)any — специальный generic-тип, распаковывается вызовом unwrap()
    C)any хранит только строки, другой тип надо маршалить через JSON
    D)any — псевдоним interface{}; тип достают ассерцией x.(T)
    показать ответ и разбор
    +D)any — псевдоним interface{}; тип достают ассерцией x.(T)

    // разбор: any — введённый в 1.18 псевдоним для interface{}: значение любого типа. Чтобы получить конкретный тип, используют type assertion x.(T) (с формой comma-ok против паники) или type switch. Это не void* и не generic-контейнер — обычный пустой интерфейс, просто с более читаемым именем.

  7. #go_generics7 / 9
    Как в Go (1.18+) объявить обобщённую функцию, работающую с типами-числами?
    A)func F(T type, x T) — тип передаётся первым обычным аргументом
    B)Только через interface{} и приведение внутри — дженериков в Go нет
    C)func F<T>(x T) — угловые скобки, как в C++ и Java
    D)func F[T Number](x T) — параметр типа в скобках [] с constraint
    показать ответ и разбор
    +D)func F[T Number](x T) — параметр типа в скобках [] с constraint

    // разбор: Дженерики появились в Go 1.18. Параметры типа объявляют в КВАДРАТНЫХ скобках после имени: func F[T Number](x T) T, где Number — constraint (интерфейс-ограничение или объединение типов). Не угловые скобки (как C++/Java) и не «тип аргументом». До 1.18 обобщённость эмулировали через interface{}, теряя типобезопасность.

  8. #go_iface_basics8 / 9
    Как тип в Go объявляет, что реализует интерфейс?
    A)Ключевым словом implements в объявлении типа
    B)Регистрацией типа в интерфейсе через reflect при старте программы
    C)Никак явно — хватает иметь все методы интерфейса (неявно)
    D)Обязательным встраиванием интерфейса полем в структуру
    показать ответ и разбор
    +C)Никак явно — хватает иметь все методы интерфейса (неявно)

    // разбор: В Go реализация интерфейсов НЕЯВНАЯ (структурная типизация): тип реализует интерфейс автоматически, если у него есть все методы с нужными сигнатурами. Ключевого слова implements нет, регистрации нет. Плюс — интерфейс можно объявить постфактум для чужого типа; минус — связь не задекларирована в коде (компилятор всё равно проверит при присваивании).

  9. #go_nil_iface9 / 9
    Что представляет собой nil-интерфейс (var e error = nil)?
    A)Пару без типа и без значения — оба компонента пусты
    B)Указатель на нулевой объект интерфейса, лежащий в куче
    C)Значение с уже заданным типом error, но пустыми данными
    D)Специальный объект-одиночку, общий для всех интерфейсов сразу
    показать ответ и разбор
    +A)Пару без типа и без значения — оба компонента пусты

    // разбор: Интерфейсное значение равно nil тогда и только тогда, когда пусты ОБА компонента — и динамический тип, и данные. var error = nil — именно такое. Как только в интерфейс кладут значение с конкретным типом (даже типизированный nil-указатель), компонент типа заполняется, и интерфейс перестаёт быть равен nil. Здесь корень ловушки typed nil.

это 9 из 82

Ещё 73 вопросов по теме — в тренажёре, с движком повторения

Прочитать разбор и ответить самому — разные навыки. В Сеньорчике вопросы идут сессиями, а движок возвращает подтемы, где вы ошибаетесь, пока они не начнут отскакивать. Бесплатно, лимит по энергии.

Частые вопросы