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

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

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

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

Наши каналы: https://t.me/proglibrary/9197
Download Telegram
💬 Что такое Low order bits (LOB) в контексте типа map в Go?

LOB в контексте типа map в Go относятся к младшим битам хэш-значения ключа, используемых для определения позиции элемента в массиве бакетов внутри мапы.

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

Вместо использования всего хэш-кода напрямую, часто используются только его младшие биты, поскольку они обеспечивают равномерное распределение элементов по бакетам, что важно для эффективности хэш-таблицы.
👍121
🏃 Самоучитель по Go для начинающих. Часть 9. Структуры и методы. Интерфейсы. Указатели. Основы ООП

В этом уроке самоучителя подробно рассмотрим структуры, методы и интерфейсы в Go, уделим особое внимание их особенностям и применению. В заключение познакомимся с конструкциями type assertion и type switch.

👉 Читать гайд

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

1. Особенности и сфера применения Go, установка, настройка
2. Ресурсы для изучения Go с нуля
3. Организация кода. Пакеты, импорты, модули. Ввод-вывод текста.
4. Переменные. Типы данных и их преобразования. Основные операторы
5. Условные конструкции if-else и switch-case. Цикл for. Вложенные и бесконечные циклы
6. Функции и аргументы. Области видимости. Рекурсия. Defer
7. Массивы и слайсы. Append и сopy. Пакет slices
8. Строки, руны, байты. Пакет strings. Хеш-таблица (map)
👍21🔥1🤔1
💬 Какие основные кейсы использования закрытых каналов в Go?

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

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

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

🔸 Тайм-ауты и отмены: в сочетании с контекстами, закрытие канала может использоваться для реализации тайм-аутов или отмены операций. Когда контекст закрывается (например, по истечению времени тайм-аута), это можно использовать как сигнал для остановки работы горутины.

📌 Использование в паттернах:

🔹 Producer-Consumer: в паттерне, где производители генерируют данные, а потребители их обрабатывают, закрытие канала может сигнализировать потребителям о том, что больше данных производиться не будет.

🔹 Fan-out, Fan-in: в этом паттерне несколько горутин могут обрабатывать данные конкурентно (fan-out), а затем результаты собираются в одном месте (fan-in). Закрытие канала может использоваться для уведомления о том, что все горутины завершили свою работу и можно начинать процесс fan-in.
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

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

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

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

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
var digitRegexp = regexp.MustCompile("[0-9]+")

func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
return digitRegexp.Find(b)
}


💬 В чем проблема кода, представленного выше?

Функция FindDigits загружает файл в память и ищет в нем первую группу подряд идущих цифр, возвращая их в виде нового среза.

Этот код работает как заявлено, но возвращаемый []byte указывает на массив, содержащий весь файл. Поскольку срез ссылается на оригинальный массив, пока срез сохраняется, сборщик мусора не может освободить массив; несколько полезных байтов файла удерживают в памяти все его содержимое.

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

func CopyDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
b = digitRegexp.Find(b)
c := make([]byte, len(b))
copy(c, b)
return c
}


Более краткая версия этой функции также может быть создана с использованием append.
🔥15👍51
💡Как тривиально проверить значения интерфейса на nil?

В Go новички часто сталкиваются с проблемой интерфейсных переменных, которым присваивается nil указатель. В таком случае, хотя значение в интерфейсе является nil, сама переменная интерфейса не равна nil.

Пример: создаем переменную x как указатель на int, который по умолчанию nil, и переменную y как пустой интерфейс, который тоже nil по умолчанию. После присваивания x переменной y, интерфейс y уже не является nil, хотя x все еще nil.


var x *int
var y any
y = x


📌 Что вернет y == nil?

Вернет false. Это потому, что интерфейс не просто представляет значение, которое ему присвоено, а действует как контейнер для этого значения.

Для проверки, является ли значение в интерфейсе nil, нужно использовать утверждение типа. Например, для проверки y на nil, используем:


y.(*int) == nil


Это показывает, что интерфейс y не nil, но содержащееся в нем значение — nil. Полный пример здесь.

#tip
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🤔41🔥1
💬 Для чего предназначен Go workspaces и какие ключевые кейсы использования?

Workspaces представлен в Go 1.18 и предназначен для управления многомодульной разработкой. Простыми словами, это инструмент для оптимизации рабочего процесса при работе с несколькими модулями, что особенно полезно в крупномасштабных проектах или при тестировании гипотез с локальными изменениями.

📌 Основные юзкейсы:

☑️ Разработка нескольких связанных модулей: если у нас есть несколько Go-модулей, которые разрабатываются вместе, Go workspaces упрощает их совместное тестирование.
☑️ Локальные изменения в зависимостях: если нам нужно внести изменения в один модуль и сразу же протестировать их в другом, workspaces упрощают этот процесс, позволяя работать с локальными копиями модулей.
☑️ Эксперименты с новыми фичами: при добавлении новых функций или исправлении ошибок, мы можем использовать workspaces для быстрого переключения между разными версиями модулей.

📦 Подробнее
6
💬 Что такое сериализация?

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

Сериализация важна для передачи данных между различными частями программы или между различными системами, особенно в распределенных системах и веб-приложениях.

📌 Простой пример в Go:

1. JSON-сериализация:
type User struct {
Name string
Age int
}
user := User{Name: "Alice", Age: 30}
jsonString, _ := json.Marshal(user)

2. Десериализация: обратный процесс, преобразование JSON в структуру Go.
var user User
json.Unmarshal(jsonString, &user)
13👍3
💬 Какие барьеры памяти существуют и как эта концепция используется в Go?

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

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

📌 Основные типы барьеров памяти:

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

2. Store barrier (барьер записи): обеспечивает, что все операции записи, произведенные до барьера, будут выполнены до операций записи после барьера.

3. Full memory barrier (полный барьер памяти): комбинирует функции барьера чтения и записи. Он гарантирует, что все операции чтения и записи до барьера будут завершены перед любыми операциями чтения и записи, следующими за барьером.

4. Acquire barrier: предотвращает перемещение операций чтения и записи, которые следуют за барьером, до него. Это обеспечивает, что все изменения памяти, выполненные другими потоками, видимы в текущем потоке перед выполнением кода после барьера.

5. Release barrier: предотвращает перемещение операций чтения и записи, которые предшествуют барьеру, после него. Это гарантирует, что все изменения в памяти, сделанные текущим потоком, будут видны другим потокам после выполнения барьера.

В контексте Go, концепция барьеров памяти обрабатывается несколько иначе по сравнению с низкоуровневыми языками, такими как C или C++.

Go предлагает более высокоуровневые абстракции для работы с конкурентностью, упрощая безопасное управление состоянием между горутинами. Основные механизмы синхронизации в Go включают: каналы, мьютексы и атомарные операции.
👍8🤔1
💬 Зачем нужен sync.map, если обычный тип map можно завернуть в мьютекс?

📌 Несколько ключевых преимуществ sync.map:

🔸 sync.Map оптимизирован для кейсов, когда чтение происходят чаще, чем запись. Он позволяет множеству горутин безопасно и одновременно читать данные из мапы без блокировки друг друга. В отличие от этого, использование мьютекса с обычной мапой блокирует доступ других горутин к мапе при чтении или записи, что может стать узким местом в программе.

🔸 sync.Map предоставляет некоторые методы, которые могут безопасно использоваться без явной блокировки, такие как Load, Store, и Delete. Это обеспечивает более высокую производительность.

🔸 В sync.Map реализована оптимизация распределения памяти, что может быть полезно в кейсах с большим количеством операций добавления и удаления.
👍121
💡Стек или куча?

🤔 Живет ли переменная на стеке вызовов, или она динамически выделена в куче?

В большинстве случаев вам не стоит беспокоиться об этом. Go собирает мусор и автоматически очищает неиспользуемые переменные.

Однако сборка мусора имеет свою цену, поэтому чем меньше выделений делает ваш код, тем быстрее он может работать.

📌 Как узнать, выделяется ли переменная в куче?

Некоторые операции по умолчанию вызывают выделение памяти в куче и поэтому легко обнаруживаются и исправляются. Вот несколько примеров:

🔸Строковые переменные неизменяемы. Конкатенация двух строк приводит к новой аллокации и сборке мусора. В качестве альтернативы можно использовать strings.Builder.
🔸Срезы, которые растут за пределы своей емкости, реаллоцируются. Решение: предварительно выделить срез с помощью make().
🔸Когда функция создает локальную переменную и возвращает указатель на эту переменную, переменная должна быть выделена в куче.

📌 Однако есть ситуации, когда выделения в куче неочевидны. Подумайте об указателях, скрытых внутри других типов данных, таких как срезы или мапы. Или рассмотрите массивы. Если массив слишком большой, чтобы жить на стеке, он выделяется в куче.

📌 Как найти эти случаи выделения в куче?

Запустите или скомпилируйте свой код с флагом сборки мусора "-m", и команда Go выведет заметку каждый раз, когда переменная перемещается или уходит со стека в кучу:

go run -gcflags "-m" 
или
go tools compile -m


#tip
👍61
👨‍💻Мок-собеседование на позицию сеньор Go-разработчика

Даниил Подольский и Владимир Балун проводят собес сеньор Go-разработчика Антона Зиновьева. Вас ждут две части: общие вопросы и лайв-кодинг.

📺 Смотреть
🥱3👍21
💬 Что такое транзакции и какие бывают уровни изоляции транзакций в контексте баз данных?

👉 Транзакции — это последовательность операций, которые либо полностью выполняются, либо не выполняются вовсе, обеспечивая свойства ACID (атомарность, согласованность, изоляция, долговечность).

👉 Выбор уровня изоляции зависит от требований к консистентности данных и допустимости параллелизма транзакций.

📌 Уровни изоляции транзакций определяют, как данные видны другим транзакциям и как они защищены от одновременных изменений. Уровни включают:

1. Read uncommitted: наименьший уровень изоляции, позволяет читать незафиксированные данные, что может привести «грязному» чтению.
2. Read committed: позволяет избежать «грязного» чтения, но не устраняет феномены неповторяемого чтения и фантомного чтения.
3. Repeatable read: предотвращает неповторяемые чтения, но может не предотвратить фантомное чтение.
4. Serializable: самый высокий уровень изоляции, который предотвращает фантомное чтение, но может снижать производительность из-за блокировок.

🔗 Подробнее на Хабре или в Википедии
👍131
🚀System Design 101

Готовитесь к собеседованию по проектированию систем или просто хотите понять принцип работы сложных систем? Тогда репозиторий ByteByteGo точно для вас.

👉 GitHub
👍53
💬 Что такое эвакуация данных в контексте типа map в Go?

Увеличение количества бакетов в Go и распределение существующих пар ключ-значение называется эвакуацией данных.

Принятие решения о выполнении эвакуации зависит от значения load factor (среднее заполнение бакетов). В Go значение loadFactor равно 6.5, то есть процесс эвакуации начинается, когда средняя заполняемость бакетов достигает 6.5 или 80% для бакета с размером 8.

Также на выполнение эвакуации в Go влияет количество связанных бакетов.
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

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

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

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

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
👍1
💬 Для чего предназначена директива //go:generate?

//go:generate — это директива в Go, используемая для генерации кода перед компиляцией. Она вставляется в комментарии и указывает инструменту go generate, что и как должно быть сгенерировано.

Когда мы запускаем go generate в директории нашего пакета, Go ищет все директивы //go:generate в исходных файлах и выполняет указанные команды.

📌 Вот как это работает:

1. Директива //go:generate размещается в комментарии внутри исходника Go. Обычно это делается в начале файла, но она может быть расположена где угодно в коде.

2. Стандартный формат директивы — //go:generate за которым следует команда, которую нужно выполнить. Например: //go:generate go run generator.go.

3. Когда мы запускаем go generate в директории пакета, Go перебирает все файлы в директории, ищет директивы //go:generate и выполняет соответствующие команды. Это может включать запуск скриптов генерации кода, инструментов для автоматизации и т. д.

💡 go:generate часто используется для автоматизации повторяющихся задач, таких как генерация дополнительного кода из шаблонов или интерфейсов, автоматическое создание моков для тестирования, обновление документации и т. д.
👍10🙏1
💬 Что такое индексы и составные индексы в контексте баз данных (например, MySQL)? Для чего используется инструкция EXPLAIN?

Индексы являются инструментом для оптимизации SQL-запросов. Они ускоряют доступ к данным, сокращая количество операций чтения и сравнения.

🔸 Индексы — это отсортированные наборы значений для конкретных колонок. Они позволяют базе данных быстрее находить строки, соответствующие условиям запроса, особенно в больших таблицах.

🔸 Составные индексы — это индексы, построенные на нескольких колонках. Они полезны для запросов, которые используют несколько колонок в условиях WHERE, JOIN или ORDER BY. Порядок колонок в составном индексе важен, так как он влияет на эффективность индекса.

🔸 Инструкция EXPLAIN в MySQL используется для анализа того, как выполняются SQL-запросы. Она показывает, какие индексы используются, сколько строк должно быть прочитано, и помогает определить, как можно оптимизировать запросы. EXPLAIN особенно полезна для понимания работы составных индексов и для проверки, использует ли запрос индекс эффективно.

👉 Подробнее
5❤‍🔥1👍1
💬 В чем ключевые различия между HTTP/1.1, HTTP/2 и HTTP/3?

🔹 HTTP/1.1 — текстовый протокол, который использует одно соединение для каждого запроса, что может вызывать задержки из-за очередей запросов (Head-of-Line Blocking) и неэффективно использовать сетевые ресурсы.

🔹 HTTP/2 — бинарный протокол, поддерживающий мультиплексирование запросов через одно соединение для уменьшения задержек, приоритизацию потоков для оптимизации загрузки и сжатие заголовков для сокращения объёма передаваемых данных.

🔹 HTTP/3 использует протокол QUIC вместо TCP, улучшая скорость установления соединений, уменьшая задержки благодаря независимой передаче данных в разных потоках и повышая эффективность восстановления после потерь пакетов.
🔥18👏1
🏃 Самоучитель по Go для начинающих. Часть 10. Введение в ООП. Наследование, абстракция, полиморфизм, инкапсуляция

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

👉 Читать гайд

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

1. Особенности и сфера применения Go, установка, настройка
2. Ресурсы для изучения Go с нуля
3. Организация кода. Пакеты, импорты, модули. Ввод-вывод текста.
4. Переменные. Типы данных и их преобразования. Основные операторы
5. Условные конструкции if-else и switch-case. Цикл for. Вложенные и бесконечные циклы
6. Функции и аргументы. Области видимости. Рекурсия. Defer
7. Массивы и слайсы. Append и сopy. Пакет slices
8. Строки, руны, байты. Пакет strings. Хеш-таблица (map)
9. Структуры и методы. Интерфейсы. Указатели. Основы ООП
👍5