Наверное, многим знакомо - пишешь ты на языке (вот скажем, Go) уже не первый год - а на собеседовании всё равно найдут чем удивить :) Вот поделюсь уловом последних дней - не смейтесь над моей наивностью - вдруг кому пригодится!

Суета вокруг defer-а

Дефером мы часто пользуемся (ну хотя бы чтобы мьютексы разлочить) но немного запутать им всё-таки можно. Что напечатает такой код?

package main

func pipa(x int) {
    println("pipa", x)
}

func main() {
    a := 3
    defer pipa(a)
    defer func() {
        println("fufu", a)
    }()
    a += 2
    println("main", a)
}

Думаю этим вряд ли кого-то из читателей Хабра подловить можно. Подсказкой может служить вопрос (простой) - когда вычисляются аргументы для defer-red функции.

Паника в горутине

Если в горутине возникнет паника - что произойдёт? Вот и весь вопрос, но для точности пусть будет и пояснение в виде кода - что он напечатает?

package main

import "time"

func main() {
	go func() {
		panic("Ah, Oh!")
	}()
	time.Sleep(100 * time.Millisecond)
	println("Hi Friend!")
}

Тут два основных варианта ответа - нужно просто быть в курсе. Проведя опрос среди коллег я убедился что 2/3 отвечают правильно - но всё же логика авторов языка тут неочевидна :-)

Что ты такое interface{}

Просят сказать что напечатает, код в котором есть переменная указатель и переменная any:

package main

func main() {
	var s *string
	var i interface{}
	println(s == nil)
	println(i == nil)
	i = s
	println(i == nil)
}

принты показывают что обе переменные равны nil но когда присвоишь одну другой, уже не nil - почему? Можно для размышления распечатать значения самих переменных - как подсказал интервьюер тут полезно понять что же такое переменная типа interface{} :)

Закрытый канал

Что будет при попытке прочесть из закрытого канала? Паника. А если в нём есть данные (буферизированные, непрочитанные). А как определить без паники что канал закрыт? Если вам приходится достаточно часто каналами пользоваться, скорее всего вы посмеётесь над лёгкостью вопроса. А тем кто не уверен предложим этот код для проверки:

package main

func main() {
	c := make(chan string, 3)
	c <- "blaha"
	c <- "muha"
	close(c)
	for {
		s, ok := <-c
		if !ok {
			break
		}
		println("msg: " + s)
	}
}

Всё верно, буфер можно вычитать, а ok оповестит что дальше канал закрыт и ждать там нечего.

Опять присваивание "к интерфейсу"

Немного похоже на "фокус с интерфейсом" выше. Или не похоже? А может одно и то же?

Что выведет этот код:

package main

type Animal struct {
	voice string
}

func (a Animal) MakeNoise() {
	println(a.voice)
}

type NoiseMaker interface {
	MakeNoise()
}

func main() {
	bob := Animal{"meow"}
	var nm NoiseMaker = bob
	bob.voice = "wof!"
	nm.MakeNoise()
}

Очевидно что-то где-то копируется вопреки "задумке". Но в какой именно момент?

Множественная аггрегация

Структура включает в себе две меньших - и для них обеих определён один и тот же метод. Какой вызовется - первый или второй?

package main

type A struct {
	v int
}

func (a A) sqr() int {
	return a.v * a.v
}

type B struct {
}

func (b B) sqr() int {
	return 13
}

type C struct {
	A
	B
}

func main() {
	c := C{A{13}, B{}}
	println(c.sqr())
}

А может будет ошибка компиляции, или паника? Если вы хоть раз с этим сталкивались, ответ, конечно, дать легко :-)

Что вы помните про Go Memory Model

Если вы видели этот небольшой мануал - он на самом деле не столько про организацию памяти, сколько про разрешение рейс-кондишнов, необходимость синхронизации и т.п. В общем-то очень важные и нужные вещи...

Но предваряет этот длинный текст короткий список с пометкой Advice - и я всегда с радостью говорю что лучше всего мне запомнился последний (кажется, четвёртый) совет из этого списка.

Don't be clever.

Согласитесь, звучит замечательно и по-философски, хоть в контексте, хоть без - я адресую это авторам всех хитроумных вопросов на собеседованиях :-)

Комментарии (2)


  1. Octagon77
    10.09.2025 06:44

    Подсказкой может служить вопрос (простой) - когда вычисляются аргументы для defer-red функции.

    Служить не может, ибо спрашивают, скорее всего, порядок выполнения ибо это нужно тупо знать. Вариант Go логичней с точки зрения реализации, альтернатива - может быть удобней для чтения.

    Проведя опрос среди коллег я убедился что 2/3 отвечают правильно - но всё же логика авторов языка тут неочевидна :)

    Логика именно что очевидна. Альтернатива приводит к возникновнию минимуо одной новой сущности, типа специальной "паники в горутине", и открывает следующий вопрос - а не сделать ли по-разному в зависомости от того, в каком потоке ОС горутина выполняется. А если вспомнить, что ограниченный до отсутствия доступ к планировщику - стратегическое решение, то вдвойне очевидна.

    Можно для размышления распечатать значения самих переменных - как подсказал интервьюер тут полезно понять что же такое переменная типа interface{} :)

    Какая душка этот интервьюер... Я бы сказал жёстче и в морду. А теперь вот задумался - если бы, как по моему, изгнать всех кто делал из себя нейросеть обучаясь на примерах - останется кто или уже кранты...

    Если вы хоть раз с этим сталкивались, ответ, конечно, дать легко :)

    Ой, пропаганда упомянутого выше метода обучения. А почему было не попросить исправить код и узнать даже больше - я не понимаю.


    1. RodionGork Автор
      10.09.2025 06:44

      я не понимаю.

      что вам мешает написать собственную статью на свой вкус вместо пространных брюзжащих комментов - я тоже не понимаю :)

      А если вспомнить, что ограниченный до отсутствия доступ к планировщику - стратегическое решение, то вдвойне очевидна.

      да ну, это ваше личное восприятие. если бы это было логично то было бы не менее логично чтобы main дожидался окончания работы всех запущенных горутин.

      единственная внятная логика в том что асинхронно запущенная процедура должна быть асинхронной и максимально независимой от остальных. всё остальное - ересь.

      ибо спрашивают, скорее всего, 

      там кроме порядка выполнения как раз и порядок вычисления аргументов же задействован. нагляднее было бы только использовать в аргументе функцию с сайд-эффектом но это уж слишком толсто