Golang | Вопросы собесов
4.33K subscribers
26 photos
695 links
Download Telegram
🤔 Что такое iota?

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

🚩Основные характеристики

🟠Инициализация с нуля
Начинает счет с 0 в каждой новой группе констант.
🟠Автоматическое увеличение
Каждое последующее использование iota в одной группе констант увеличивает его значение на 1.
🟠Повторное использование
При каждом новом объявлении константного блока iota сбрасывается до 0.

package main

import "fmt"

const (
A = iota // 0
B // 1
C // 2
)

func main() {
fmt.Println(A) // Вывод: 0
fmt.Println(B) // Вывод: 1
fmt.Println(C) // Вывод: 2
}


Использование его для создания битовых флагов
package main

import "fmt"

const (
Flag1 = 1 << iota // 1 << 0 = 1
Flag2 // 1 << 1 = 2
Flag3 // 1 << 2 = 4
Flag4 // 1 << 3 = 8
)

func main() {
fmt.Println(Flag1) // Вывод: 1
fmt.Println(Flag2) // Вывод: 2
fmt.Println(Flag3) // Вывод: 4
fmt.Println(Flag4) // Вывод: 8
}


Сброс его в новом блоке
package main

import "fmt"

const (
X = iota // 0
Y // 1
)

const (
Z = iota // 0 (новый блок констант, iota сбрасывается)
W // 1
)

func main() {
fmt.Println(X) // Вывод: 0
fmt.Println(Y) // Вывод: 1
fmt.Println(Z) // Вывод: 0
fmt.Println(W) // Вывод: 1
}


🚩Комплексное использование

Можно использовать в выражениях и совместно с другими константами для создания более сложных последовательностей.
package main

import "fmt"

const (
_ = iota // пропускаем 0
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20 = 1048576
GB // 1 << 30 = 1073741824
)

func main() {
fmt.Println("KB:", KB) // Вывод: KB: 1024
fmt.Println("MB:", MB) // Вывод: MB: 1048576
fmt.Println("GB:", GB) // Вывод: GB: 1073741824
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Чем горутины отличаются от тредов

Горутины — это легковесные потоки выполнения в Go, которые управляются рантаймом Go и потребляют меньше ресурсов, чем обычные потоки (треды). В отличие от потоков, горутины могут выполняться совместно на одном или нескольких потоках, что позволяет Go эффективно использовать многопоточность. Горутины легко создавать и завершать, их переключение выполняется быстрее, что делает их подходящими для масштабируемых параллельных задач.

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

EXPLAIN — это команда в SQL, которая показывает, как база данных выполняет SQL-запрос. Она помогает оптимизировать запросы, анализируя их план выполнения.

🚩Как работает?

Когда вы пишете EXPLAIN перед SQL-запросом, база данных не выполняет его, а показывает пошаговый процесс выполнения. Это помогает понять:
Какие индексы используются
Какие таблицы сканируются
Какие соединения (JOIN) выполняются
Оценить производительность запроса
EXPLAIN SELECT * FROM users WHERE age > 30;


Выход (пример)
Seq Scan on users  (cost=0.00..25.00 rows=10 width=100)


🚩`EXPLAIN ANALYZE` — глубокий анализ

Добавляет реальное время выполнения запроса
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;


🚩Оптимизация запросов с `EXPLAIN`

Использование индексов
CREATE INDEX idx_users_age ON users(age);


Правильный порядок JOIN
EXPLAIN SELECT * FROM orders JOIN users ON orders.user_id = users.id;


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

ACID – это принципы целостности транзакций в базах данных:
- A (Atomicity) – транзакция либо выполняется полностью, либо не выполняется вовсе.
- C (Consistency) – после транзакции БД остается в согласованном состоянии.
- I (Isolation) – параллельные транзакции не влияют друг на друга.
- D (Durability) – данные сохраняются даже в случае сбоя системы.


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

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

Легковесность
Горутины потребляют значительно меньше памяти и ресурсов по сравнению с потоками ОС. Каждая горутина стартует с размером стека порядка 2 КБ, тогда как поток ОС требует гораздо большего размера стека (обычно несколько мегабайт).

Планировщик Go
Горутины управляются встроенным планировщиком Go, а не планировщиком ОС. Планировщик Go распределяет выполнение горутин по доступным потокам ОС, используя концепцию "M:N" (много горутин на несколько потоков).

Отсутствие необходимости ручного управления
Создание, синхронизация и управление горутинами намного проще благодаря встроенным средствам Go, таким как каналы (channels) и sync-пакет. В то время как работа с потоками ОС требует дополнительных усилий для синхронизации (мьютексы, условные переменные и т.д.).

Автоматическое управление стеком
Стек горутины автоматически увеличивается или уменьшается в зависимости от потребностей, что позволяет эффективно использовать память.

Простота и удобство
Синтаксис и использование горутин интуитивно понятны. Для запуска достаточно добавить go перед вызовом функции:

package main

import (
"fmt"
"time"
)

func sayHello() {
for i := 0; i < 5; i++ {
fmt.Println("Hello")
time.Sleep(100 * time.Millisecond)
}
}

func main() {
go sayHello() // Запускаем горутину
fmt.Println("World")
time.Sleep(1 * time.Second) // Даем горутине время завершиться
}


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

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

Основные структуры данных в Go включают массивы, слайсы, карты (map), структуры (struct) и каналы (channel). Каждая из этих структур имеет свои особенности использования и предназначение.

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

Да, между SSL (Secure Sockets Layer) и TLS (Transport Layer Security) есть отличия. TLS является улучшенной и более безопасной версией SSL.

🚩История и версия

🟠SSL:
SSL 1.0: Никогда не был выпущен публично из-за серьезных уязвимостей.
SSL 2.0: Выпущен в 1995 году, но вскоре был признан небезопасным из-за множества уязвимостей.
SSL 3.0: Выпущен в 1996 году, значительно улучшил безопасность, но со временем также был признан устаревшим из-за уязвимостей (например, POODLE-атака).

🟠TLS:
TLS 1.0: Выпущен в 1999 году как обновление SSL 3.0. Включает исправления безопасности и улучшения.
TLS 1.1: Выпущен в 2006 году с дополнительными защитами от некоторых атак.
TLS 1.2: Выпущен в 2008 году, поддерживает современные алгоритмы шифрования и хеширования.
TLS 1.3: Выпущен в 2018 году, значительно улучшена безопасность и производительность, упрощен процесс установки соединения.

🚩Технические отличия

🟠Алгоритмы шифрования:
SSL: Поддерживает более старые и менее безопасные алгоритмы шифрования.
TLS: Поддерживает более современные и безопасные алгоритмы шифрования. TLS 1.3 исключает поддержку устаревших алгоритмов и предлагает только современные безопасные алгоритмы.

🟠Процесс рукопожатия (Handshake):
SSL: Более сложный процесс рукопожатия, включающий несколько шагов, что делает его уязвимым для некоторых атак.
TLS: Улучшенный процесс рукопожатия, включая использование HMAC (Hash-based Message Authentication Code) для обеспечения целостности сообщения. TLS 1.3 значительно упрощает и ускоряет процесс рукопожатия.

🟠Целостность данных:
SSL: Использует комбинацию MD5 и SHA-1 для целостности данных, что не так безопасно по современным стандартам.
TLS: Использует HMAC с SHA-256 и другими современными алгоритмами для обеспечения целостности данных.

🟠Управление сеансами:
SSL: Меньше возможностей для управления сеансами.
TLS: Включает улучшенные механизмы для управления сеансами, такие как возобновление сеансов, что позволяет экономить время и ресурсы при повторных подключениях.

🚩Безопасность

🟠SSL: Уязвим для ряда атак, таких как POODLE, BEAST и другие, из-за устаревших и менее безопасных методов шифрования и проверки целостности.
🟠TLS: Значительно более безопасен благодаря устранению уязвимостей SSL и внедрению современных методов шифрования и проверки целостности. TLS 1.3 еще более безопасен благодаря исключению устаревших методов и упрощению процесса рукопожатия.

🚩Совместимость

🟠SSL: Практически не используется в современных системах из-за известных уязвимостей и устаревших методов безопасности.
🟠TLS: Широко поддерживается и используется в современных браузерах, серверах и других сетевых устройствах. TLS 1.2 и TLS 1.3 являются наиболее часто используемыми версиями.

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

Пустая строка ("") в Go — это структура string, которая содержит:
- указатель на данные (0 байт),
- длину строки (int — 8 байт на 64-битной архитектуре).
Таким образом, даже пустая строка весит 16 байт (указатель + длина), без учёта хранимых данных.


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

Слайсы являются ссылочными типами, поэтому простое присваивание одного слайса другому создаст новую ссылку на тот же подлежащий массив. Если вы хотите создать копию слайса с независимым подлежащим массивом, можно использовать встроенную функцию copy или методы, такие как использование append.

🚩Способы копирования слайса

🟠Использование функции `copy`
Создает побайтовую копию элементов из одного слайса в другой.
package main

import "fmt"

func main() {
original := []int{1, 2, 3, 4, 5}

// Создаем новый слайс той же длины, что и оригинал
copySlice := make([]int, len(original))

// Копируем элементы из оригинального слайса в новый
copy(copySlice, original)

// Изменяем элемент в копии
copySlice[0] = 100

fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}


Использование функции
inal)   


Чтобы создать новый слайс с копированными элементами.
package main

import "fmt"

func main() {
original := []int{1, 2, 3, 4, 5}

// Копируем элементы из оригинального слайса в новый слайс
copySlice := append([]int(nil), original...)

// Изменяем элемент в копии
copySlice[0] = 100

fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}


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

- Лёгкие по памяти (обычно килобайты, а не мегабайты).
- Масштабируемы — можно запускать тысячи горутин.
- Управляются внутренним планировщиком Go, а не ОС.
- Быстро переключаются между задачами.
- Просты в использовании (каналы, select, go).
Это делает горутины особенно эффективными для серверной разработки и высоконагруженных систем.


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

Замыкание (closure) — это функция, которая запоминает и использует переменные из своей внешней области видимости, даже если эта область видимости уже закончила своё выполнение.

🚩Как это работает?

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

import "fmt"

func counter() func() int {
count := 0
return func() int {
count++
return count
}
}

func main() {
inc := counter() // создаём замыкание
fmt.Println(inc()) // 1
fmt.Println(inc()) // 2
fmt.Println(inc()) // 3

newInc := counter() // новое замыкание с новой переменной count
fmt.Println(newInc()) // 1
}


🚩Где полезно использовать?

Счётчики (как в примере выше). Фабричные функции, создающие специфичные обработчики. Ограничение доступа к данным (инкапсуляция).

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Зачем нужен foreign key?

Foreign key (внешний ключ) — это ограничение в базе данных, обеспечивающее связь между таблицами и целостность данных.
Он:
- Предотвращает вставку «висячих» записей (без связанных данных).
- Позволяет БД контролировать каскадное удаление/обновление.
- Делает структуру БД более безопасной и логичной.


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

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

🚩Ключевая разница

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

Пример 1: Фильтрация по HAVING
Задача: Вывести товары, у которых продано более 10 единиц.
SELECT product, SUM(quantity) as total_sold
FROM sales
GROUP BY product
HAVING SUM(quantity) > 10;


Пример 2: Разница между WHERE и HAVING
SELECT category, COUNT(*) as total_products
FROM products
WHERE price > 100 -- Убирает дешёвые товары ДО группировки
GROUP BY category
HAVING COUNT(*) > 5; -- Оставляет только категории с более 5 товаров


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

Планирование горутин управляется M:N моделью, где:
- G (goroutine) — лёгкая задача.
- M (machine) — системный поток.
- P (processor) — логическая единица исполнения, выполняющая G на M.
Планировщик:
- Назначает горутины на доступные процессоры.
- Переключает задачи при блокировке.
- Использует стратегию work-stealing, чтобы равномерно загружать потоки.
- Работает независимо от ОС.


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


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

🚩Композиция

Позволяет включать одну структуру в другую, что дает возможность использовать методы встроенной структуры. Это часто называют "встраиванием" или "композицией" вместо наследования.
package main

import "fmt"

// Определение структуры
type Engine struct {
Power int
}

func (e Engine) Start() {
fmt.Println("Engine started with power:", e.Power)
}

// Определение другой структуры, которая включает первую
type Car struct {
Brand string
Engine
}

func main() {
myCar := Car{
Brand: "Toyota",
Engine: Engine{Power: 150},
}

fmt.Println("Car brand:", myCar.Brand)
myCar.Start() // Вызов метода встроенной структуры
}


🚩Интерфейсы

Определяют набор методов, которые должны быть реализованы типом. Любой тип, реализующий все методы интерфейса, автоматически рассматривается как реализующий этот интерфейс. Это дает возможность полиморфизма.
package main

import "fmt"

// Определение интерфейса
type Drivable interface {
Drive()
}

// Определение структуры, реализующей интерфейс
type Car struct {
Brand string
}

func (c Car) Drive() {
fmt.Println(c.Brand, "is driving")
}

// Еще одна структура, реализующая интерфейс
type Bike struct {
Brand string
}

func (b Bike) Drive() {
fmt.Println(b.Brand, "is driving")
}

// Функция, принимающая интерфейс
func StartDriving(d Drivable) {
d.Drive()
}

func main() {
car := Car{Brand: "Toyota"}
bike := Bike{Brand: "Yamaha"}

StartDriving(car)
StartDriving(bike)
}


🚩Встраивание интерфейсов

Интерфейсы также могут быть встроены друг в друга, что позволяет создавать сложные структуры интерфейсов.
package main

import "fmt"

// Определение базового интерфейса
type Printer interface {
Print()
}

// Определение другого интерфейса, включающего первый
type AdvancedPrinter interface {
Printer
Scan()
}

// Реализация структуры, реализующей расширенный интерфейс
type MultiFunctionPrinter struct{}

func (m MultiFunctionPrinter) Print() {
fmt.Println("Printing...")
}

func (m MultiFunctionPrinter) Scan() {
fmt.Println("Scanning...")
}

func main() {
mfp := MultiFunctionPrinter{}
mfp.Print()
mfp.Scan()
}


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

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


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

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

🚩Основные компоненты Go `runtime`

Горутины (goroutines) — лёгкие потоки, управляемые Go.
Планировщик (scheduler) — распределяет горутины по потокам ОС.
Модель памяти — управление стеком и кучей.
Сборщик мусора (GC) — автоматически очищает неиспользуемую память.
Syscalls — взаимодействие с ОС.

🚩Горутины и планировщик (scheduler)

Горутины легче, чем потоки ОС: Go может запускать миллионы горутин, а планировщик (M:N) распределяет их по потокам ОС.
Go использует M:N-модель, где:
- M — системные потоки (OS threads).
- N — горутины (goroutines).
- P — процессоры (logical processors) — управляют выполнением горутин.
P привязан к M, а G (горутины) распределяются между `P` динамически.
Это позволяет Go эффективно использовать CPU без ручного управления потоками.
Goroutine (G1, G2, G3, ...) 

Scheduler → P (Processor) → M (OS Thread) → CPU


🚩Управление памятью и стеком

Стек (stack) в Go динамический — он начинается с 2 KB и увеличивается при необходимости.
Если стек заполнен, Go автоматически расширяет его.
В отличие от C, Go не требует malloc/free, так как есть GC (garbage collector).

🚩Сборщик мусора (Garbage Collector)

Go использует автоматический сборщик мусора, который:
Работает параллельно с программой
Минимизирует паузы (low-latency GC)
Очищает неиспользуемые объекты из кучи
import "runtime"

runtime.GC() // Принудительный запуск сборщика мусора (обычно не нужно)


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

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


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

Составной индекс (Composite Index) — это индекс, который создаётся сразу на нескольких колонках таблицы базы данных. Он помогает ускорить поиск и сортировку данных, особенно если запросы используют условия по нескольким полям.

🚩Зачем нужен составной индекс?

🟠Оптимизация запросов
Если часто выполняются запросы с фильтрацией по нескольким колонкам (WHERE col1 = X AND col2 = Y), составной индекс ускоряет их выполнение.
🟠Ускорение сортировки
Если запросы используют ORDER BY col1, col2, индекс помогает избежать дополнительной сортировки.
🟠Снижение нагрузки на сервер
Без индекса СУБД вынуждена выполнять полный перебор (Full Table Scan), что занимает больше времени.

🚩Как работает составной индекс?

Он строится по нескольким колонкам и фактически представляет собой отсортированную структуру данных. Например, в PostgreSQL или MySQL создаётся так:
CREATE INDEX idx_name ON users (last_name, first_name);


Теперь база данных будет использовать индекс для запросов:
SELECT * FROM users WHERE last_name = 'Иванов' AND first_name = 'Петр';


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

В Go мапа (map[K]V) — это указатель на внутреннюю хеш-структуру. Её "вес" при передаче — 8 байт (64-битная архитектура), так как это просто ссылка.
Но фактический размер в памяти зависит от количества элементов и структуры хеш-таблицы, которая может занимать значительно больше.


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

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

🚩Неизменяемость

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

🚩Структура строки

Внутренне строка представлена структурой, которая содержит два поля:
Указатель на массив байтов: Это указатель на первый элемент массива байт, который фактически хранит символы строки в кодировке UTF-8.
Длина: Количество байт в строке, а не количество рун или символов. Это важное различие, поскольку в UTF-8 один символ может занимать от 1 до 4 байт.

🚩UTF-8 как стандартная кодировка

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

🚩Срезы строк

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

🚩Производительность и память

Благодаря неизменяемости и способу хранения строк в виде срезов байтов, Go обеспечивает эффективное управление памятью и производительность при работе со строками. Однако необходимо быть осторожным с операциями, которые могут казаться невинными, но приводят к частому созданию новых строк, так как это может повлечь за собой издержки на выделение памяти и сборку мусора.
s := "Hello, world"      // Создание строки
t := s[7:] // Срез строки, создает новую строку "world"

fmt.Println(s) // Выводит: Hello, world
fmt.Println(t) // Выводит: world


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM