Golang | Вопросы собесов
4.34K subscribers
28 photos
700 links
Download Telegram
🤔 Как происходит поиск по ключу в map?

Карты (maps) реализованы на основе хеш-таблиц, что обеспечивает быстрый доступ к значениям по ключам. Давайте рассмотрим, как происходит поиск по ключу в карте, и какие этапы включены в этот процесс.

🚩Основные этапы

🟠Хеширование ключа
Сначала вычисляется хеш-значение ключа. Функция хеширования преобразует ключ в целое число, которое служит индексом в хеш-таблице.

🟠Поиск в хеш-таблице
Хеш-значение используется для доступа к соответствующей "ячейке" или "корзине" (bucket) в хеш-таблице.

🟠Поиск в корзине
Если корзина содержит несколько элементов (из-за коллизий хеширования), Go выполняет линейный поиск среди этих элементов, сравнивая ключи с использованием оператора ==.

🚩Детали

🟠Хеширование ключа
Когда вы пытаетесь получить значение по ключу, Go сначала вычисляет хеш-значение этого ключа. Хеш-функция берет ключ (например, строку или целое число) и преобразует его в индекс хеш-таблицы.

🟠Доступ к корзине
Хеш-значение указывает на конкретную корзину в хеш-таблице. Корзина может содержать один или несколько элементов. В случае коллизий (когда несколько ключей хешируются в один и тот же индекс) корзина может содержать связанный список или другой механизм для хранения нескольких элементов.

🟠Линейный поиск внутри корзины
Если корзина содержит несколько элементов, Go выполняет линейный поиск среди этих элементов. Для каждого элемента в корзине сравнивается ключ с искомым ключом с использованием оператора ==. Если ключи совпадают, возвращается соответствующее значение. Если ключ не найден, возвращается нулевое значение типа (zero value) и флаг, указывающий на отсутствие ключа.

package main

import "fmt"

func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}

value, exists := myMap["Alice"]
if exists {
fmt.Println("Alice:", value) // Alice: 25
} else {
fmt.Println("Alice not found")
}

value, exists = myMap["Charlie"]
if exists {
fmt.Println("Charlie:", value)
} else {
fmt.Println("Charlie not found") // Charlie not found
}
}


🚩Подводные камни и особенности

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

🟠Производительность
В среднем, доступ к элементу в карте осуществляется за константное время O(1), что делает карты очень эффективными для поиска по ключу. Однако в худшем случае, при большой нагрузке коллизий, производительность может деградировать до линейного времени O(n).

🟠Изменение карты во время поиска
Карты не являются потокобезопасными. Если одна горутина изменяет карту, в то время как другая горутина читает из нее, это может привести к панике. Для обеспечения потокобезопасности используйте мьютексы или структуру sync.Map.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Из каких частей состоит HTTP-запрос?

HTTP-запрос включает:
- Стартовую строку: метод (GET, POST), путь (/api), версия (HTTP/1.1)
- Заголовки (headers): информация о клиенте, типах данных, авторизации и т.д.
- Пустая строка: разделитель между заголовками и телом
- Тело (body): данные запроса (не всегда есть — например, у GET нет)


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как сделать свои методы для пакета?

В Go методы создаются для структур (или типов) внутри пакета. Это позволяет добавлять логику и поведение объектам.

🚩Создание собственного пакета

Допустим, мы создаем пакет mathutils, который будет содержать метод для структуры Calculator.
package mathutils

// Calculator - структура с данными
type Calculator struct {
A, B int
}

// Sum - метод для сложения чисел A и B
func (c Calculator) Sum() int {
return c.A + c.B
}


🚩Использование пакета в другом файле

Теперь мы можем использовать этот метод в основном файле программы.
package main

import (
"fmt"
"mypackage/mathutils" // Импортируем наш пакет
)

func main() {
calc := mathutils.Calculator{A: 5, B: 3}
fmt.Println("Sum:", calc.Sum()) // Выведет: Sum: 8
}


🚩Указатели vs. Значения в методах

Методы можно объявлять как для значений (func (c Calculator)) так и для указателей (func (c *Calculator)).
Когда использовать указатели?
Если метод изменяет данные структуры.
Чтобы избежать копирования больших структур.
func (c *Calculator) Multiply(factor int) {
c.A *= factor
c.B *= factor
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как устроена многозадачность в Go?

Go использует горутины — лёгкие, кооперативные потоки:
- Управляются внутренним планировщиком, а не ОС.
- Планировщик Go мапит большое количество горутин на малое количество системных потоков (M:N модель).
- Горутины создаются быстро, с минимальными ресурсами.
- Взаимодействуют через каналы и select.
Многозадачность реализуется через кооперативную конкуренцию и распределение задач по worker-потокам.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как расшифровывается аббревиатура ACID?

ACID — это набор свойств транзакций в базах данных, обеспечивающий надежность и целостность данных.

🚩ACID

🟠A (Atomicity) — Атомарность
Транзакция выполняется либо полностью, либо не выполняется вовсе.
Пример: Если при переводе денег со счета A на счет B ошибка произошла на полпути, изменения откатываются.

🟠C (Consistency) — Согласованность
Данные остаются в правильном состоянии до и после транзакции.
Пример: Если сумма на всех счетах банка должна оставаться неизменной, транзакция не должна нарушить это правило.

🟠I (Isolation) — Изолированность
Одновременные транзакции не мешают друг другу.
Пример: Два клиента покупают один и тот же товар, но база данных правильно обрабатывает, кто купил первым.

🟠D (Durability) — Долговечность
После завершения транзакции изменения сохраняются, даже если система сломается.
Пример: Если заказ оформлен, он не исчезнет при внезапном отключении электричества.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
📅 Осталось 7 дней до конца краудфандинга

Мы на финишной прямой!

Если ты планировал присоединиться, но ещё не успел, сейчас идеальный момент.

Вознаграждения за поддержку:

🚀 PRO подписка к easyoffer 2.0 на 1 год по цене месячной подписки. Активировать подписку можно в любой момент, например, когда начнешь искать работу.
Приглашение на закрытое бета-тестирование

👉 Поддержать easyoffer 2.0

Не откладывай на последний момент

📌 Если не получается оплатить через карту РФ — напишите мне @kivaiko, и мы найдём удобный способ
🤔 Что известно про паттерн Singleton (Одиночка)?

Singleton гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к нему.
Характеристики:
- Ленивая инициализация (создаётся при первом вызове).
- Применяется для объектов, которые должны быть уникальны: логгеры, конфигурация, доступ к БД.
- В Go реализуется через глобальные переменные и sync.Once для потокобезопасной инициализации.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Как использовать линтеры (linters)?

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

🟠Популярные линтеры для Go
В Go есть несколько популярных линтеров:
golangci-lint – самый мощный и популярный, объединяет множество линтеров.
go vet – стандартный инструмент для поиска ошибок.
golint – проверяет стиль кода (но устарел).
staticcheck – анализирует код на ошибки и неэффективность.

🟠Установка линтера
Устанавливаем golangci-lint (лучший вариант)
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest


После установки проверьте версию:
golangci-lint --version


🟠Запуск линтера
Запустить проверку в проекте можно так:
golangci-lint run


Можно проверить только определённый файл:
golangci-lint run myfile.go


Если хотите автоматически исправлять ошибки, используйте:
golangci-lint run --fix


🟠Использование `go vet` (встроенный анализатор)
Go уже имеет встроенный линтер
go vet ./...


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое type switch?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие циклы есть в Go?

Существует один основной цикл — это цикл for. н может использоваться в различных формах, выполняя функции традиционных циклов while, do-while и классического for.

🚩Формы цикла

С тремя выражениями
      package main

import "fmt"

func main() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}


Как while
      package main

import "fmt"

func main() {
i := 0
for i < 5 {
fmt.Println(i)
i++
}
}


Бесконечный
      package main

import "fmt"

func main() {
i := 0
for {
if i >= 5 {
break
}
fmt.Println(i)
i++
}
}


С использованием range
      package main

import "fmt"

func main() {
arr := []int{1, 2, 3, 4, 5}
for index, value := range arr {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
}



🚩Примеры

Итерация по массиву
      arr := [5]int{10, 20, 30, 40, 50}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}


Итерация по карте
      m := map[string]int{"a": 1, "b": 2, "c": 3}
for key, value := range m {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}


Итерация по строке
      s := "hello"
for index, char := range s {
fmt.Printf("Index: %d, Char: %c\n", index, char)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое recover?

Recover — это механизм восстановления после ошибки. В языках вроде Go recover используется для перехвата паники и безопасного продолжения работы программы.
Обобщённо, "recover" означает стратегию, при которой система или компонент не падает окончательно, а пытается вернуть управление, залогировать ошибку или выполнить корректную очистку.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Насколько безопасно передавать слайсы в разные горутины?

Передача слайсов (slices) в разные горутины может быть безопасной или небезопасной в зависимости от того, как вы используете эти слайсы. Основная проблема заключается в доступе к общим данным из разных горутин, что может привести к состояниям гонки (race conditions), если не соблюдать определенные правила.

🚩Основные аспекты безопасности

🟠Иммутабельность (неизменяемость)
Если слайс передается в горутину только для чтения, то это безопасно. Иммутабельные данные (данные, которые не изменяются) могут свободно использоваться в нескольких горутинах без дополнительной синхронизации.
package main

import (
"fmt"
"sync"
)

func printSlice(slice []int, wg *sync.WaitGroup) {
defer wg.Done()
for _, v := range slice {
fmt.Println(v)
}
}

func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
wg.Add(2)

go printSlice(slice, &wg)
go printSlice(slice, &wg)

wg.Wait()
}


🟠Синхронизация доступа
Если слайс передается в горутину для записи или для одновременного чтения и записи, необходимо обеспечить синхронизацию доступа к данным. Для этого можно использовать мьютексы (sync.Mutex) или другие механизмы синхронизации.
package main

import (
"fmt"
"sync"
)

func incrementSlice(slice []int, wg *sync.WaitGroup, mu *sync.Mutex) {
defer wg.Done()
for i := range slice {
mu.Lock()
slice[i]++
mu.Unlock()
}
}

func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
var mu sync.Mutex

wg.Add(2)

go incrementSlice(slice, &wg, &mu)
go incrementSlice(slice, &wg, &mu)

wg.Wait()
fmt.Println(slice)
}


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

import (
"fmt"
"sync"
)

func incrementSlice(slice []int, wg *sync.WaitGroup) {
defer wg.Done()
for i := range slice {
slice[i]++
}
}

func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup

wg.Add(2)

// Передаем копии слайса в горутины
go incrementSlice(append([]int(nil), slice...), &wg)
go incrementSlice(append([]int(nil), slice...), &wg)

wg.Wait()
fmt.Println(slice) // Исходный слайс не изменяется
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
Офигеть, вот это поддержка! 🔥

Скажу честно: когда я планировал запуск краудфандинговой кампании, в голове были разные варианты развития событий. Думал — ну, наверное, получится собрать 300 тысяч. В самом идеальном сценарии — может быть, миллион.

Но больше всего я боялся, что запущу кампанию, и не получится собрать даже 300 т. Это был бы провал. Так много усилий, времени и денег вложено в проект… и если бы всё закончилось ничем — это бы сильно демотивировало.

Но, ребята, мы превысили изначальную цель в 10 раз —
3 031 040 рублей! 🤯

Вся эта кампания — это одна большая проверка бизнес-модели на прочность. И я супер рад, что запустил всё публично. Люди видят, что EasyOffer реально нужен. Теперь нет сомнений — проект актуален, он будет прибыльным и будет развиваться.

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

Никак не могу отделаться от мысли, что easyoffer — это ведь мой первый сайт. Учебный, пет-проект, просто для портфолио. И вот что из него вышло. Просто офигеть.

Я не зря ушёл с работы, чтобы заниматься только им.
Я поверил в этот проект — и сейчас вижу, что вы тоже в него верите. Для меня это очень многое значит.

Огромное спасибо за вашу поддержку! ❤️
🤔 Что будет, если элемент не вмещается в размер слайса?

Если добавляемый элемент превышает текущую ёмкость (capacity) слайса, append создаёт новый массив с увеличенной ёмкостью (обычно в два раза больше исходной), копирует существующие элементы и добавляет новый. Это может привести к перераспределению памяти.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое HAVING?

HAVING — это оператор в SQL, который фильтрует группированные (GROUP BY) данные по агрегатным функциям (SUM, COUNT, AVG, MAX, MIN).

🚩Чем отличается `HAVING` от `WHERE`?

WHERE фильтрует отдельные строки до группировки.
HAVING фильтрует группы строк после GROUP BY.

Теперь посчитаем сумму продаж по категориям и оставим только те, где сумма > 250
SELECT category, SUM(amount) AS total_sales
FROM sales
GROUP BY category
HAVING SUM(amount) > 250;


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
Осталось 3 дня!

Финальный отсчёт пошёл — осталось всего 3 дня до окончания краудфандинга easyoffer 2.0

Сейчас можно получить максимум пользы за минимальные деньги. После окончания кампании цены вырастут и вознаграждения станут недоступны.

👉 Поддержи easyoffer 2.0 и получи:

🚀 PRO подписка к easyoffer 2.0 на 1 год по цене месячной подписки. Активировать подписку можно в любой момент, например, когда начнешь искать работу. Приглашение на закрытое бета-тестирование

Поддержи проект сейчас, чтобы не забыть!

📌 Если не получается оплатить через карту РФ — напишите мне @kivaiko, и мы найдём удобный способ
🤔 Что такое индексы в MySQL?

Это структуры данных, которые ускоряют поиск строк в таблицах MySQL. Они работают аналогично оглавлению в книге, позволяя БД быстро находить нужные записи без полного сканирования таблицы.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 У ресивера имеется звёздочка - что это значит?

В Go метод можно привязывать как к значению структуры, так и к указателю на структуру.
Если у ресивера (receiver) перед именем типа стоит *, это значит, что метод принимает указатель на структуру, а не саму структуру.

🚩Разница между `T` и `*T` в методах

🟠Метод с ресивером-значением (`T`)
Метод работает с копией структуры, а не с оригиналом.
package main

import "fmt"

type Person struct {
Name string
}

// Метод работает с копией, оригинал не изменится
func (p Person) SetName(name string) {
p.Name = name
}

func main() {
p := Person{Name: "Alice"}
p.SetName("Bob")
fmt.Println(p.Name) // Выведет: Alice (не изменилось)
}


🟠Метод с ресивером-указателем (`*T`)
Метод работает с оригиналом и может изменять его поля.
type Person struct {
Name string
}

// Метод изменяет оригинал структуры
func (p *Person) SetName(name string) {
p.Name = name
}

func main() {
p := Person{Name: "Alice"}
p.SetName("Bob")
fmt.Println(p.Name) // Выведет: Bob (изменилось!)
}


🚩 Когда использовать `*T`?

Если метод изменяет структуру → нужен указатель (*T).
Если метод только читает данные → можно использовать значение (T).
Использование *T также избегает копирования больших структур.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
Завтра последний день!

Краудфандинг заканчивается уже завтра, и второй попытки не будет.

👉 Поддержи easyoffer 2.0 и получи:

🚀 PRO подписка к easyoffer 2.0 на 1 год по цене месячной подписки. Активировать подписку можно в любой момент, например, когда начнешь искать работу. Приглашение на закрытое бета-тестирование

📌 Если не получается оплатить через карту РФ — напишите мне @kivaiko, и мы найдём удобный способ
🤔 Какие типы каналов существуют?

В Go существует два типа каналов: буферизованные (buffered) и небуферизованные (unbuffered). Небуферизованные каналы требуют, чтобы отправляющая и принимающая горутина синхронизировались друг с другом, что делает их блокирующими. Буферизованные каналы имеют определённый размер буфера, и горутина может отправить сообщение в канал, не ожидая немедленного получения, пока буфер не заполнится. Оба типа каналов используются для передачи данных между горутинами и синхронизации их работы.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
🚨 Последний шанс!

Сегодня — последний день краудфандинга.
Через несколько часов всё закроется, и больше невозможно будет поучаствовать.

Если ты хотел, но откладывал — СЕЙЧАС самое время. Займёт 2 минуты, но изменит твой подход к собеседованиям надолго.

Поддержи easyoffer 2.0 и получи:

🚀 PRO подписка к easyoffer 2.0 на 1 год по цене месячной подписки. Активировать подписку можно в любой момент, например, когда начнешь искать работу. Приглашение на закрытое бета-тестирование

PRO подписка к easyoffer 2.0:

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

Доступ к лучшим ответам на вопросы

Список самых частых задач, которые задаются на собеседовании + их фильтрация по грейдам и компаниям

Доступ к лучшим ответам на задачи

Список тестовых заданий компаний + лучшее решение

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

Доступ к тренажеру "Реальное собеседование", который позволит тренироваться проходить собеседование в конкретную компанию

До конца кампании — остались часы.
Поддержать: https://planeta.ru/campaigns/easyoffer

📌 Если не получается оплатить через карту РФ — напишите мне @kivaiko, и мы найдём удобный способ