Библиотека Go для собеса | вопросы с собеседований
6.88K subscribers
220 photos
6 videos
1 file
424 links
Вопросы с собеседований по Go и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/0b524a15

Для обратной связи: @proglibrary_feeedback_bot

Наши каналы: https://t.me/proglibrary/9197
Download Telegram
💬 Допустимо ли возвращать ответ "HTTP 200 OK", когда на стороне сервера произошла ошибка (сведения об ошибке будут содержаться внутри тела ответа)?

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

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

В случае возникновения ошибки следует использовать соответствующие статусы ответа HTTP, которые точно отражают природу проблемы. Например:

🔹 500 Internal Server Error — для неустранимых ошибок на стороне сервера.
🔹 503 Service Unavailable — если сервер временно недоступен, например, из-за перегрузки или технического обслуживания.
🔹 400 Bad Request — если ошибка возникла из-за некорректных данных, предоставленных клиентом.
🔹 404 Not Found — если запрос был направлен на несуществующий ресурс.

🔗 Все коды состояния ответа HTTP
🔗 Обсуждение на StackOverflow
5
💬 Что из себя представляет механизм method value и чем он полезен?

Method value — механизм, который позволяет ссылаться на метод объекта с привязкой к конкретному экземпляру этого объекта. Это значит, что мы можем сохранить ссылку на метод определённого экземпляра и использовать эту ссылку для вызова метода позже, при этом метод автоматически будет вызываться для связанного с ним экземпляра.

📌 Как это работает: когда мы берём метод от экземпляра структуры или типа, Go автоматически создаёт функцию, которая "замыкает" этот экземпляр внутри себя. Эта функция при вызове будет применять метод к тому экземпляру, для которого она была создана.

📌 Пример:


type Counter struct {
value int
}

func (c *Counter) Increment() {
c.value++
}

func main() {
c := &Counter{value: 10}
increment := c.Increment // Сохраняем method value
increment() // Вызываем метод через сохранённую ссылку
fmt.Println(c.value) // Выведет 11
}


В примере increment является method value, которое привязано к конкретному экземпляру c. Вызов increment() эквивалентен вызову c.Increment().

Method value особенно полезны в ситуациях, когда необходимо передать метод как аргумент функции или сохранить метод для последующего вызова. Это позволяет использовать методы объектов так, как если бы они были обычными функциями, при этом сохраняя контекст вызова внутри метода.
👍25🥱3🤔1
💬 Чем отличаются сигналы Linux? Какие можно перехватить?

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

📌 Основные различия:

1. Синхронные сигналы — вызываются ошибками в программе (например, деление на ноль). Эти сигналы отправляются напрямую процессу, выполняющему ошибочное действие.
2. Асинхронные сигналы — посылаются внешними процессами или системой. Например, SIGKILL или SIGTERM, отправляемые для завершения процесса.

📌 Перехватываемые и неперехватываемые сигналы:

🔹 Перехватываемые сигналы могут быть обработаны программой. Программа может определить функцию-обработчик для таких сигналов, изменяя стандартное поведение. Например, SIGTERM и SIGUSR1 можно перехватить и обработать, выполнив определённые действия перед завершением программы или инициированием других процедур.
🔹 Неперехватываемые сигналы нельзя перехватить или проигнорировать. Эти сигналы немедленно выполняют своё стандартное действие. Примером неперехватываемого сигнала является SIGKILL, который всегда немедленно завершает процесс.

📌 Примеры перехватываемых сигналов:
🔹 SIGTERM — просит процесс завершиться. Это корректный способ попросить программу завершить свою работу.
🔹 SIGHUP — уведомляет процесс о потере управляющего терминала. Часто используется для перезагрузки конфигураций сервисов.
🔹 SIGUSR1, SIGUSR2 — резервируются для использования в пользовательских приложениях.

📌 Примеры неперехватываемых сигналов:
🔹 SIGKILL — немедленно завершает процесс. Не может быть перехвачен или обработан.
🔹 SIGSTOP — останавливает (приостанавливает) процесс до получения сигнала SIGCONT.
👍192
💬 Что такое идемпотентность?

Идея идемпотентности (тождественности влияния) зародилась в алгебре, где описывает определенные свойства некоторых математических операций.

В мире программирования операция считается идемпотентной, если ее однократное выполнение имеет тот же эффект, что и многократное. Например, операция присваивания x = 1 идемпотентна, потому что после ее выполнения x всегда будет хранить 1, независимо от того, сколько раз ее выполнить.

Точно так же HTTP-метод PUT является идемпотентным, поскольку многократная отправка ресурса в какое-либо место ничего не изменит: повторная отправка не даст ничего нового. Операция x += 1, однако, не является идемпотентной, потому что после каждого ее выполнения создается новое состояние.
👍115
💬 В чем преимущество использования iota в Go?

iota — это предопределенное значение, которое можно использовать в объявлении const для создания последовательности связанных значений.
Использование приема с iota избавляет от необходимости вручную присваивать значения константам. Вместо этого можно записать такое определение:

type EventType byte
const (
_ = iota // iota == 0; игнорировать нулевое значение EventDelete
EventType = iota // iota == 1
EventPut // iota == 2; неявное присваивание
)


В объявлении константы iota представляет последовательно увеличивающиеся нетипизированные целочисленные значения, которые можно использовать для создания набора связанных констант. В начале каждого объявления const идентификатор iota получает нулевое значение и затем увеличивается с каждой операцией присваивания значения новой константе (независимо от использования ссылки на идентификатор iota).

Поскольку iota является нетипизированным числом, его можно использовать для присваивания типизированных значений без явного приведения типов, даже константе с типом float64:

const (
u = iota * 42 // iota == 0; u == 0 (нетипизированная целочисленная константа)
v float64 = iota * 42 // iota == 1; v == 42.0 (константа типа float64)
)


Ключевое слово iota допускает неявное перечисление, что делает тривиальным создание произвольно длинных наборов связанных констант, как это показано в следующем примере, где перечисляются различные единицы измерения размеров в байтах:

type ByteSize uint64

const (
_ = iota
KB ByteSize = 1 << (10 * iota) MB
GB
TB
PB
)
👍11
💬 Почему следует избегать использования context.Background() напрямую? Какие есть альтернативы?

Использование context.Background() напрямую не рекомендуется, потому что он не предоставляет способа остановить или отменить операции, если что-то пойдет не так. Этот контекст самый простой, без значений, сроков и сигналов отмены. Это может стать проблемой, когда задачи застревают или требуют плавного завершения.

Чтобы справиться с этим, лучше использовать context.WithTimeout, context.WithCancel или context.WithDeadline. Эти контексты позволяют задавать время ожидания или возможность отмены, что делает горутины более управляемыми и надежными.

📌 Вот примеры использования:

🔸 context.WithTimeout(ctx, duration): задает время ожидания для выполнения задачи.
🔸 context.WithCancel(ctx): позволяет отменить задачу вручную.
🔸 context.WithDeadline(ctx, deadline): устанавливает конкретное время завершения задачи.

Можно также использовать функции с суффиксом Cause (например, context.WithTimeoutCause), которые дают более детальные сообщения об ошибках (например, "context deadline exceeded: custom message").

В случае работы с каналами, чтобы не ждать ответа бесконечно, можно использовать конструкцию select с тайм-аутом:

select {
case result := <-ch:
fmt.Println("Received result:", result)
case <-time.After(5 * time.Second):
fmt.Println("Timed out")
}


Однако, time.After может привести к краткосрочным утечкам памяти. В таких случаях лучше использовать time.Timer или time.Ticker для лучшего контроля над временем.
👍3
Самые полезные каналы для программистов в одной подборке!

Сохраняйте себе, чтобы не потерять 💾

🔥Для всех

Библиотека программиста — новости, статьи, досуг, фундаментальные темы
Книги для программистов
IT-мемы
Proglib Academy — тут мы рассказываем про обучение и курсы

🤖Про нейросети
Библиотека робототехники и беспилотников | Роботы, ИИ, интернет вещей
Библиотека нейрозвука | Транскрибация, синтез речи, ИИ-музыка
Библиотека нейротекста | ChatGPT, Gemini, Bing
Библиотека нейровидео | Sora AI, Runway ML, дипфейки
Библиотека нейрокартинок | Midjourney, DALL-E, Stable Diffusion

#️⃣C#

Книги для шарпистов | C#, .NET, F#
Библиотека шарписта — полезные статьи, новости и обучающие материалы по C#
Библиотека задач по C# — код, квизы и тесты
Библиотека собеса по C# — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Вакансии по C#, .NET, Unity Вакансии по PHP, Symfony, Laravel

☁️DevOps

Библиотека devops’а — полезные статьи, новости и обучающие материалы по DevOps
Вакансии по DevOps & SRE
Библиотека задач по DevOps — код, квизы и тесты
Библиотека собеса по DevOps — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования

🐘PHP

Библиотека пхпшника — полезные статьи, новости и обучающие материалы по PHP
Вакансии по PHP, Symfony, Laravel
Библиотека PHP для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по PHP — код, квизы и тесты

🐍Python

Библиотека питониста — полезные статьи, новости и обучающие материалы по Python
Вакансии по питону, Django, Flask
Библиотека Python для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Python — код, квизы и тесты

Java

Книги для джавистов | Java
Библиотека джависта — полезные статьи по Java, новости и обучающие материалы
Библиотека Java для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Java — код, квизы и тесты
Вакансии для java-разработчиков

👾Data Science

Книги для дата сайентистов | Data Science
Библиотека Data Science — полезные статьи, новости и обучающие материалы по Data Science
Библиотека Data Science для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Data Science — код, квизы и тесты
Вакансии по Data Science, анализу данных, аналитике, искусственному интеллекту

🦫Go

Книги для Go разработчиков
Библиотека Go разработчика — полезные статьи, новости и обучающие материалы по Go
Библиотека Go для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Go — код, квизы и тесты
Вакансии по Go

🧠C++

Книги для C/C++ разработчиков
Библиотека C/C++ разработчика — полезные статьи, новости и обучающие материалы по C++
Библиотека C++ для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по C++ — код, квизы и тесты
Вакансии по C++

💻Другие каналы

Библиотека фронтендера
Библиотека мобильного разработчика
Библиотека хакера
Библиотека тестировщика
Вакансии по фронтенду, джаваскрипт, React, Angular, Vue
Вакансии для мобильных разработчиков
Вакансии по QA тестированию
InfoSec Jobs — вакансии по информационной безопасности

📁Чтобы добавить папку с нашими каналами, нажмите 👉сюда👈

Также у нас есть боты:
Бот с IT-вакансиями
Бот с мероприятиями в сфере IT

Мы в других соцсетях:
🔸VK
🔸YouTube
🔸Дзен
🔸Facebook *
🔸Instagram *

* Организация Meta запрещена на территории РФ
👍1
👩‍💻 errors.Is(), errors.As(), errors.Unwrap(), кастомные ошибки и многое другое: подробное руководство для Go-разработчика

👉 Читать
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
💬 Почему использование chan struct{} вместо chan bool предпочтительнее для сигнализации между горутинами?

🔹
chan struct{} сразу показывает, что канал используется исключительно для сигнализации, тогда как chan bool может вызвать путаницу, так как значения true и false могут иметь разный смысл.

🔹 Тип struct{} не занимает памяти — это просто сигнал. Это приводит к небольшой, но все равно оптимизации памяти.

🔹 chan struct{} исключает возможность неправильного использования канала для передачи данных, что может произойти при использовании chan bool.

🔹 Для одноразового сигнала можно просто закрыть канал, что является понятным и эффективным способом передать сигнал нескольким получателям без отправки данных.

📌 Пример:

type JobDispatcher struct {
start chan struct{}
}

func NewJobDispatcher() *JobDispatcher {
return &JobDispatcher{
start: make(chan struct{}),
}
}

func (j *JobDispatcher) Start() {
close(j.start)
}
👍18
💬 Как можно оптимизировать многократные вызовы одной и той же функции в Go, чтобы избежать выполнения одной и той же работы несколько раз?

Можно использовать пакет singleflight. Он гарантирует, что независимо от того, сколько раз вызывается функция в один и тот же период, она будет выполнена только один раз, и результат этого вызова будет возвращен всем вызывающим.

📌 Пример использования:


var group singleflight.Group

func UsingSingleFlight(key string) {
v, _, _ := group.Do(key, func() (any, error) {
return FetchExpensiveData()
})

fmt.Println(v)
}


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

Основное преимущество использования singleflight заключается в том, что он предотвращает многократное выполнение одной и той же работы, что особенно полезно для ресурсоемких операций или операций, которые нельзя выполнять одновременно (например, ping() на сервер). В отличие от кеша, singleflight не только сохраняет результаты, а также координирует выполнение функции.
👍131
💬 Как использовать context.AfterFunc для выполнения функции после отмены контекста и что происходит, если контекст уже отменен?

В Go функция context.AfterFunc (Go 1.21 +) позволяет запланировать выполнение функции после завершения контекста, будь то из-за отмены или тайм-аута. Она запускает функцию в новой горутине сразу после того, как канал ctx.Done родительского контекста отправляет сигнал.

📌 Пример использования:


ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel()

stop := context.AfterFunc(ctx, func() {
fmt.Println("Cleanup operations after context is done")
})


Если контекст уже отменен на момент вызова AfterFunc, функция f будет выполнена немедленно в новой горутине.

Функция stop() позволяет отменить запланированную функцию, если она еще не начала выполняться. Если stop() возвращает true, это означает, что функция была успешно остановлена до выполнения. Если stop() возвращает false, это означает, что функция уже начала выполняться или была остановлена ранее.

📌 Пример использования stop():


stop := context.AfterFunc(ctx, func() {
// some cleanup code
})

if stopped := stop(); stopped {
fmt.Println("Remove the callback before context is done")
}


Функция AfterFunc полезна для выполнения задач очистки, логирования или других операций, которые необходимо выполнить после отмены контекста.
👍12
💬 Почему использование time.Sleep() может быть проблематичным в Go-программах, и как можно улучшить управление паузами, чтобы учитывать контекст выполнения?

Использование time.Sleep() может быть проблематичным, потому что оно не учитывает контекст выполнения и не может быть прервано. Например, если приложение получает сигнал на завершение работы, функция, использующая time.Sleep(), не сможет сразу прекратить выполнение, а продолжит выполнение только после завершения периода сна. Это может привести к задержкам в завершении работы приложения и другим проблемам.

Чтобы улучшить управление паузами и учитывать контекст выполнения, лучше использовать конструкции, которые могут реагировать на сигналы контекста. Например, можно использовать функцию time.After() в сочетании с select, чтобы обрабатывать паузы и проверку контекста:

func doWork(ctx context.Context, d time.Duration) {
for {
select {
case <-ctx.Done():
return
case <-time.After(d):
}

...
}
}


Также можно использовать time.Timer для более эффективного управления таймерами:

func doWork(ctx context.Context, d time.Duration) {
delay := time.NewTimer(d)

for {
select {
case <-ctx.Done():
if !delay.Stop() {
<-delay.C
}
return
case <-delay.C:
_ = delay.Reset(d)
}

...
}
}


Этот подход позволяет функции немедленно завершиться при получении сигнала завершения контекста, предотвращая утечки памяти и обеспечивая более предсказуемое поведение программы.
👍13🤔1
✉️ Как завалить собеседование, даже не начав его: 8 ошибок в сопроводительных письмах

Откликаетесь, но сразу получаете отказы? Не торопитесь с выводами — возможно, все дело в вашем сопроводительном письме.

👉Сопроводительное — это первое впечатление, которое мы производим на эйчара, а первое впечатление, как известно, очень важно.

Собрали для вас несколько распространенных ошибок по составлению такого письма — а в статье по ссылке можно найти остальные ошибки и пример идеального сопроводительного.

Кстати, вакансии можно поискать в наших профильных каналах:
🤮Data Science, анализ данных, аналитика
🤮Python
🤮Frontend
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤔1
💬 Почему важно следить за временем жизни горутин и как мы можем избежать проблем с утечкой памяти в Go?

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

📌 Чтобы избежать проблем с утечкой памяти, необходимо:

1. Использовать контексты (context.Context): контексты позволяют контролировать время выполнения горутины и отменять её выполнение, когда это необходимо. Например, использование select с контекстом позволяет горутине завершиться корректно при получении сигнала отмены:

func Job(ctx context.Context, d time.Duration) {
for {
select {
case <-ctx.Done():
return
default:
...
time.Sleep(d)
}
}
}


2. Закрывать каналы: если горутина читает данные из канала, важно корректно закрывать этот канал, чтобы горутина завершалась и не зависала бесконечно.

func worker(jobs <-chan int) {
for i := range jobs {
...
}
}

jobs := make(chan int)
go worker(jobs)
// Закрытие канала, когда работа завершена
close(jobs)


3. Избегать использования time.Sleep() без контекста: функция time.Sleep() не поддерживает прерывания и может привести к зависанию горутины, если её необходимо завершить. Вместо этого используйте конструкции, учитывающие контекст, такие как time.After с select.
👍82
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.

Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.

Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬 Как отключить поддержку HTTP/2 на стороне клиента и сервера в Go? Почему это может понадобиться?

Можно использовать переменную окружения GODEBUG. Она позволяет управлять выполнением определенных частей программы Go.

Для отключения HTTP/2 необходимо установить GODEBUG следующим образом:

export GODEBUG=http2client=0,http2server=0


Эта команда отключит поддержку HTTP/2 по умолчанию как в HTTP-клиенте, так и в HTTP-сервере. Это может быть полезно в случае, если есть проблемы с реализацией HTTP/2 на сервере или если необходимо поддерживать совместимость с более старыми системами, которые не поддерживают HTTP/2.

При запуске программы Go с такими параметрами GODEBUG, программа будет использовать только HTTP/1.1 для всех HTTP-запросов и ответов, обходя любые потенциальные проблемы, связанные с HTTP/2.

👉 Подробнее
👍141
💬 Почему лучше использовать неэкспортируемую пустую структуру в качестве ключа контекста в Go вместо строки или другого примитивного типа?

Использование неэкспортируемой пустой структуры в качестве ключа контекста в Go предпочтительнее по нескольким причинам:

1. Уникальность: пустая структура обеспечивает уникальность в пределах области видимости пакета, что помогает избежать конфликтов, которые могут возникнуть при использовании строк или других примитивных типов в качестве ключей.
2. Легковесность: пустая структура не выделяет памяти, так как она не содержит полей, что делает ее очень легким и эффективным вариантом для использования в качестве ключа.
3. Избежание конфликтов: использование пустых структур помогает избежать конфликтов с другими пакетами, которые могут случайно использовать те же самые строки или примитивные типы в качестве ключей контекста.

Пример кода с использованием пустой структуры:


type contextKey struct{}

func main() {
ctx := context.WithValue(
context.Background(),
contextKey{}, "данные, связанные с запросом",
)

handleRequest(ctx)
}

func handleRequest(ctx context.Context) {
fmt.Println("data:", ctx.Value(contextKey{}))
}


Этот пример демонстрирует, как использование пустой структуры в качестве ключа контекста помогает обеспечить уникальность и избежать потенциальных конфликтов.
👍162