Библиотека Go для собеса | вопросы с собеседований
5.33K subscribers
134 photos
1 video
1 file
163 links
Вопросы с собеседований по Go и ответы на них.

Список наших каналов: https://t.me/proglibrary/9197
Учиться у нас: https://proglib.io/w/0b524a15

Обратная связь: @proglibrary_feedback_bot

По рекламе: @proglib_adv
Прайс: @proglib_advertising
Download Telegram
🏗️ Структуры данных для разработчиков: 10 самых важных

Структуры данных — фундамент эффективной разработки. Кратко разберем 10 ключевых структур данных, которые необходимо освоить каждому разработчику для создания производительных и масштабируемых приложений, а подробнее читайте в статье👇

🔹 Списки отлично подходят для хранения и обработки упорядоченных данных и полезны в различных приложениях, таких как управление задачами, ленты соцсетей и корзины интернет-магазинов.
🔹 Массивы — упорядоченная коллекция элементов фиксированного размера и хорошо подходят для ситуаций, где размер коллекции известен или редко меняется.
🔹 Стеки следуют принципу «последним пришел — первым вышел». Они идеальны для реализации операций отмены/повтора в текстовых редакторах или ведения истории просмотров в веб-браузерах.
🔹 Очереди работают по принципу «первым пришел — первым вышел». Они подходят для управления заданиями печати, отправки действий пользователя в играх на сервер или обработки сообщений в чат-приложениях.
🔹 Кучи используются для планирования задач и управления памятью. Они особенно полезны в реализации очередей с приоритетами, где нужен доступ к элементу с наивысшим или наименьшим приоритетом.
🔹 Деревья организуют данные иерархически. Они полезны для представления данных с естественными иерархиями или связями и могут использоваться в различных приложениях, таких как индексация баз данных.
🔹 Хеш-таблицы позволяют эффективно искать, вставлять и удалять данные. Они используют хеш-функцию для сопоставления ключей с соответствующими местами хранения и обеспечивают доступ к сохраненным значениям за постоянное время.
🔹 Суффиксные деревья специализируются на поиске строк в документах, что делает их идеальными для текстовых редакторов и алгоритмов поиска.
🔹 Графы отслеживают отношения и находят пути, что делает их незаменимыми в социальных сетях, рекомендательных системах и алгоритмах поиска путей.
🔹 KD-деревья хороши для поиска ближайших соседей и важны для картографических приложений и геолокационных сервисов.
🏃 Самоучитель по Go для начинающих. Часть 16. Тестирование кода и его виды. Table-driven подход. Параллельные тесты

В статье познакомимся с концепцией тестирования кода и её основными видами, изучим инструменты стандартного пакета testing, научимся запускать и визуализировать тесты. В качестве практического задания напишем и протестируем алгоритм «Решето Эратосфена».

👉 Читать гайд

📌 Остальные части в серии:

1. Особенности и сфера применения Go, установка, настройка
2. Ресурсы для изучения Go с нуля
3. Организация кода. Пакеты, импорты, модули. Ввод-вывод текста.
4. Переменные. Типы данных и их преобразования. Основные операторы
5. Условные конструкции if-else и switch-case. Цикл for. Вложенные и бесконечные циклы
6. Функции и аргументы. Области видимости. Рекурсия. Defer
7. Массивы и слайсы. Append и сopy. Пакет slices
8. Строки, руны, байты. Пакет strings. Хеш-таблица (map)
9. Структуры и методы. Интерфейсы. Указатели. Основы ООП
10. Введение в ООП. Наследование, абстракция, полиморфизм, инкапсуляция
11. Обработка ошибок. Паника. Восстановление. Логирование
12. Обобщенное программирование. Дженерики
13. Работа с датой и временем. Пакет time
14. Интерфейсы ввода-вывода. Буферизация. Работа с файлами. Пакеты io, bufio, os
15. Конкурентность. Горутины. Каналы
💬 Срезы в Go всегда аллоцируются в куче?

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

1. Первый случай: и срез, и базовый массив находятся на стеке.

func doSomething() {
a := byte(1)
println("a's address:", &a)

s := make([]byte, 1)
println("slice's address:", &s)
println("underlying array's address:", s)
}


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

2. Базовый массив начинается на стеке, затем перемещается в кучу.

func main() {
slice := make([]int, 0, 3)
println("slice:", slice, "- slice addr:", &slice)

slice = append(slice, 1, 2, 3)
println("slice full cap:", slice)

slice = append(slice, 4)
println("slice after exceed cap:", slice)
}


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

3. Базовый массив сразу выделяется в куче.

Если емкость среза больше 64 КБ, базовый массив будет выделен в куче, как видно в следующем примере:

func main() {
sliceA := make([]int, 64 * 1024)
sliceB := make([]int, 64 * 1024 + 1)
println("sliceA:", sliceA)
println("sliceB:", sliceB)
}


В результате массив для sliceA находится на стеке, а для sliceB — в куче.

🤔 Как избежать выделения памяти в куче?

Лучший способ — заранее оценить необходимую емкость среза, используя make() с установленной емкостью. Это уменьшит вероятность дополнительных выделений памяти. Также можно использовать sync.Pool для повторного использования массивов.
💬 Что такое процесс, системные вызовы и прерывания?

Процесс представляет собой абстракцию ОС, инкапсулирующую ресурсы определенной программы. Чаще всего под процессом понимают отдельно запущенное приложение и его компоненты: стек, регистры, открытые файлы, переменные и так далее. Каждый процесс имеет свое уникальное адресное пространство, контекст выполнения и как минимум один поток — сущность ОС для параллельного выполнения различных задач. Адресное пространство — это набор адресов, используемых процессом для обращения к памяти.

Потоками выполнения можно управлять с помощью системных вызовов и механизма прерываний. Системные вызовы предоставляют интерфейс между пользовательским процессом и ОС для обеспечения ввода / вывода, управления файлами / памятью, доступа к системным объектам.

Механизм прерываний используется для оповещения ОС о внешних событиях и передачи управления конкретному обработчику. В UNIX-подобных системах прерывания реализуются при помощи специальных сигналов из стандарта POSIX.
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

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

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

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

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬 В чем суть нового пакета unique, добавленного в Go 1.23?

Пакет unique предоставляет инструменты для канонизации значений (interning/hash-consing). Это означает, что дубликаты одного и того же значения будут храниться в памяти только один раз.

Главная идея заключается в том, что с помощью функции Make[T] можно создать специальную ссылку (объект типа Handle[T]) на каноническое представление значения.

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

👉 Подробнее
💬 Существуют ли в Go правила по расположению и наименованию файлов и функций, предназначенных для тестрования?

Файлы с тестами должны находиться в одном пакете с тестируемыми функциями или в соответствующем пакете с суффиксом _test. Название файла с тестами должно оканчиваться на _test.go.

Название тестирующей функции должно начинаться префиксом Test и далее содержать название тестируемой функции. Тест заканчивается в тот момент, когда тестирующая функция возвращает или вызывает один из методов: FailNow, Fatal, Fatalf, SkipNow, Skip, Skipf. Стоит учитывать, что они могут вызываться только из горутины, выполняющей тестирующую функцию.
❗️Задача для конкурса в честь дня программиста

Условие:

Даны две строки s и f (начальная и конечная) и словарь D (набор слов).

Нужно определить, можно ли преобразовать s в f, используя только слова из словаря D. При этом каждое преобразование должно менять только один символ, а длина слова должна оставаться неизменной. Если преобразование возможно, нужно найти кратчайшую последовательность таких преобразований и вернуть ее длину. Если преобразование невозможно, вернуть "Преобразование невозможно".

Пример ввода 1:
    D = ["cat", "cot", "dot", "dog", "bat", "dag"]
    s = "cat"
    t = "dog"

Вывод:
Минимальное количество шагов для преобразования 'cat' в 'dog': 3

Пример ввода 2:
    D = ["cat", "cot", "bat"]
    s = "cat"
    t = "dog"

Вывод:
Минимальное количество шагов для преобразования 'cat' в 'dog': Преобразование невозможно
Please open Telegram to view this post
VIEW IN TELEGRAM
📹 Все о массивах и слайсах в Go: видеогайд от Владимира Балуна

⏱️ Таймкоды:

00:00 Введение
00:47 Устройство массивов в Go
01:40 Работа с массивами в Go
10:00 Перемещение массива в стеке
11:29 Итерация по массивам в Go
15:11 Где аллоцируются массивы в Go
17:22 Педедача массива в функцию
18:16 Слайсы в Go
21:34 Реаллокация слайса в Go
24:45 Резервирование памяти под слайс
25:44 Создание слайса без инициализации
27:38 Модификация строк в Go
28:35 Приведение слайсов в строки и обратно без копирования
30:13 Передача слайса в функцию
31:12 Итерация по слайсам в Go
33:55 Оптимизация итерации по слайсам в Go
35:42 Получение слайсов в Go
42:40 Получение слайса из массива в Go
43:15 Конвертация слайса в массив в Go
44:15 Конвертация слайса в указатель на массив в Go
45:02 Указатель на нулевой массив в Go
46:18 Удаление из конца слайса в Go
46:51 Удаление из начала слайса в Go
49:02 Реализация стека и очереди в Go
50:00 Как увеличить размер слайса в Go
50:48 Как уменьшить емкость слайса в Go
54:05 Где аллоцируются слайсы в Go
59:12 Как очистить слайс в Go
01:01:51 В чем разница пустых и нулевых слайсов в Go
01:05:17 Как сравнивать слайсы в Go
01:07:53 Как скопировать данные слайса в Go
01:09:47 Почему функция appeng возвращает слайсв в Go
01:12:39 Потенциальные проблемы с функцией append в Go
01:14:10 Реализация функции append в Go
01:15:32 Утечки памяти при работе со слайсами в Go

📺 YouTube | VK Видео | Дзен | Rutube
Please open Telegram to view this post
VIEW IN TELEGRAM
Go-разработчики часто используют следующую конструкцию:

f, err := os.Create("file.txt")
if err != nil {
return err
}
defer f.Close()


Однако, для файлов с возможностью записи это может быть опасно, так как метод Close() может вернуть ошибку, которая игнорируется при использовании defer.

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

f, err := os.Create("file.txt")
if err != nil {
return err
}
if _, err := f.Write([]byte("Hello, world!")); err != nil {
f.Close()
return err
}
return f.Close()


Использование defer безопасно для чтения, но для записи стоит быть осторожнее и проверять ошибки вручную.

👉 Подробнее
Самые полезные каналы для программистов в одной подборке!

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

🔥Для всех

Библиотека программиста — новости, статьи, досуг, фундаментальные темы
Книги для программистов
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++

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

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

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

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

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

* Организация Meta запрещена на территории РФ
💬 Назовите кейсы, в которых sync.Cond может быть более подходящим выбором, чем каналы?

1. С каналом мы можем либо отправить сигнал одной горутине, отправив значение, либо уведомить все горутины, закрыв канал, но мы не можем сделать и то, и другое. sync.Cond предоставляет более детальный контроль. Мы можем вызвать Signal(), чтобы запустить отдельную горутину, или Broadcast() чтобы разбудить их все.
2. И мы можем вызывать Broadcast() столько раз, сколько нужно, чего каналы не могут делать, когда они закрыты (закрытие закрытого канала вызовет панику).
3. Каналы не предоставляют встроенного способа защиты shared данных — нам нужно будет управлять этим отдельно с помощью мьютекса. sync.Cond, с другой стороны, предлагает более комплексный подход, объединяя блокировку и сигнализацию в одном пакете (и повышая производительность).
Флаг -cpu можно использовать при запуске тестов Go, чтобы указать список значений GOMAXPROCS, с использованием которых необходимо запустить тесты. Например,
go test -cpu=4,5 


запустит тесты 2 раза. Тесты сначала будут запущены с четырьмя процессорами, а затем второй раз — с пятью.

#tip
💬 Каким образом хранится внутреннее состояние sync.WaitGroup?

Оно хранится в переменной типа atomic.Uint64, которая ключает:

🔸 Counter (старшие 32 бита): эта часть отслеживает количество горутин, которые ожидает WaitGroup. При вызове wg.Add() с положительным значением, счётчик увеличивается, а при вызове wg.Done() — уменьшается на единицу.
🔸 Waiter (младшие 32 бита): отслеживает количество горутин, которые ждут, пока счётчик достигнет нуля. Как только счётчик достигает нуля, все ожидающие горутины разблокируются.

Также есть последнее поле — sema uint32, это внутренний семафор, управляемый рантаймом Go.
🙌 Хардкорный вышмат для тех, кто интересуется ML, AI, DS

Начать с вводных занятий можно здесь, ответив всего на 4 вопроса – https://proglib.io/w/6d9d383b

Что будет на демо?

🔹Вводный урок от CPO курса;

🔹Лекции со всеми преподавателями МГУ по темам: теория множеств, непрерывность функции, основные формулы комбинаторики, матрицы и операции над ними, градиентный спуск;

🔹Практические задания и дополнительные материалы!

⚡️Переходите и активируйте – https://proglib.io/w/6d9d383b
Please open Telegram to view this post
VIEW IN TELEGRAM
💬 Что такое буферизация? Как она реализована в Go?

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

В Go для буферизации операций ввода-вывода используется встроенный пакет bufio. Он оборачивает io.Reader или io.Writer, создавая новый объект Reader или Writer, соответственно, который также реализует интерфейс, но обеспечивает буферизацию и некоторые улучшения ввода-вывода.
Пакет bufio содержит три основных типа: Reader, Writer и Scanner.
💬 Перечислите кейсы применения iota в Go.

🔸 iota и enums

Мы часто определяем константы в Go для создания списка возможных значений, которые что-то может принимать (это иногда называют enum).

const (
Planet = 0
Star = 1
Comet = 2
Galaxy = 3
// и так далее
)


Конкретные числа 0, 1, 2... здесь не имеют значения. Это просто произвольные значения, с которыми можно сравнивать объекты:

if object.Kind == Planet {
// это планета!
}


🔸 Использование iota с const

Однако поддерживать длинный список таких чисел вручную сложно. Вот где приходит на помощь iota. Это своего рода магическое, постоянно увеличивающееся значение, которое мы можем использовать для присвоения произвольных чисел константам:

const (
Planet = iota // 0
Star // 1
Comet // 2
Galaxy // 3
// ...
)


Мы фактически присваиваем iota каждой константе в списке, но Go позволяет опустить запись = iota после первой константы.

🔸 Начало iota с 1

Также мы можем использовать iota в более сложных выражениях. Например, если мы хотим, чтобы значения начинались с 1, а не с 0:

const (
January = iota + 1
February
March
// ...
)


Здесь значение для January будет 1, для February — 2 и так далее.

🔸 iota игнорирует комментарии

Кстати, можно добавлять комментарии или пустые строки в блок констант, и это не повлияет на значения iota:

const (
Electron = iota // 0
Neutron // 1
Proton // 2
Photon // 3
Gluon // 4
)


🔸 iota, флаги и битовые маски

Ещё одно распространённое применение iota — создание значений для битовых масок. Битовая маска — это способ сравнить число с бинарным значением, чтобы проверить, установлен ли конкретный бит в 1 или 0. Когда используются конкретные битовые значения, их иногда называют флагами, а число, содержащее их, — битовым полем.

Например:

const (
Bit0 = 1 << iota // 1
Bit1 // 2
Bit2 // 4
// ...
)


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

Теперь можно выполнить побитовое сравнение этих масок с интересующим нас числом:

v := 0b00000010
if v&Bit1 != 0 {
fmt.Println("Looks like bit 1 is set!")
}
// Looks like bit 1 is set!
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

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

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

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

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬 В чем разница пустых и нулевых срезов в Go?

• Нулевой срез — это срез, который имеет значение nil, и он не указывает на какой-либо выделенный блок памяти. Его длина и ёмкость равны нулю, а сам срез nil.
• Пустой срез — это срез, который ссылается на существующий, но пустой блок памяти (например, s := make([]int, 0) или s := []int{}). Его длина и ёмкость равны нулю, но сам срез не является nil.

📌 Практическая разница:
• nil-срез полезен для того, чтобы указать отсутствие данных, и в некоторых ситуациях может потребоваться, чтобы срез был именно nil.
• Пустой срез гарантирует наличие выделенной памяти, даже если в нем нет элементов, и его можно безопасно использовать для операций без дополнительной проверки на nil.