Golang | Вопросы собесов
4.51K subscribers
33 photos
1 video
786 links
Download Telegram
🤔 В чём отличие длины и ёмкости у слайса?

1. Длина (len): количество элементов, содержащихся в слайсе.
2. Ёмкость (cap): максимальное количество элементов, которые слайс может вместить без перевыделения памяти.
3. При добавлении элементов с помощью append длина увеличивается, а если она превышает ёмкость, выделяется новый блок памяти с удвоенной ёмкостью.


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

Концепции объектно-ориентированного программирования (ООП) реализованы несколько иначе, чем в традиционных ООП-языках, таких как Java или C++. Не использует классы, наследование и полиморфизм на основе классов в привычном понимании. Вместо этого он применяет интерфейсы, структуры и встраивание для достижения гибкости и мощи ООП.

🟠Структуры вместо классов
Основной способ организации и капсуляции данных — это структуры (structs). Структуры объединяют данные в одну сущность, но в отличие от классов, они не включают определение методов внутри себя. Вместо этого методы определяются отдельно и ассоциируются со структурой через определение получателя метода.
type Person struct {
Name string
Age int
}

func (p Person) Greet() string {
return "Hello, my name is " + p.Name
}


🟠Интерфейсы для полиморфизма
Реализуется через интерфейсы. Интерфейс — это набор сигнатур методов. Тип считается реализующим интерфейс, если он имеет все методы, указанные в интерфейсе. Важной особенностью интерфейсов в Go является то, что типы могут удовлетворять интерфейсам неявно, без специального объявления.
type Greeter interface {
Greet() string
}

func GreetSomeone(g Greeter) {
fmt.Println(g.Greet())
}


🟠Встраивание для композиции
Один из способов реализации композиции — встраивание структур. Можно встроить одну структуру в другую, что позволяет делегировать часть работы встроенной структуре.
type Employee struct {
Person
Position string
}

func (e Employee) Work() string {
return e.Name + " is working as a " + e.Position
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3💊1
🤔 Как прочитать строку в виде иероглифов, кириллицы и т.д.?

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


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

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

🚩Основные способы проверки работы горутины через каналы

🟠Односторонний канал для завершения горутины
Горутина может отправлять сигнал (например, true) в канал, чтобы уведомить о своем завершении.
func worker(done chan bool) {
fmt.Println("Работа началась...")
time.Sleep(2 * time.Second) // Имитация работы
fmt.Println("Работа завершена!")
done <- true // Отправляем сигнал в канал
}

func main() {
done := make(chan bool)

go worker(done) // Запускаем горутину

// Ожидаем сигнал завершения
<-done
fmt.Println("Основной поток: горутина завершена")
}


🟠Канал для передачи промежуточных результатов
Горутина может отправлять данные в канал, чтобы сигнализировать о прогрессе выполнения.
func worker(progress chan int) {
for i := 1; i <= 5; i++ {
fmt.Printf("Шаг %d выполнен\n", i)
progress <- i // Отправляем номер шага в канал
time.Sleep(500 * time.Millisecond) // Имитация работы
}
close(progress) // Закрываем канал после завершения работы
}

func main() {
progress := make(chan int)

go worker(progress) // Запускаем горутину

// Считываем данные из канала
for step := range progress {
fmt.Printf("Получен сигнал: шаг %d завершен\n", step)
}
fmt.Println("Все шаги выполнены!")
}


🟠Тайм-ауты и проверка работы через `select`
Если важно знать, работает ли горутина, но при этом нужно ограничить ожидание, используется оператор select с тайм-аутом.
func worker(status chan string) {
time.Sleep(2 * time.Second) // Имитация работы
status <- "Горутина завершена"
}

func main() {
status := make(chan string)

go worker(status)

select {
case msg := <-status:
fmt.Println(msg)
case <-time.After(1 * time.Second): // Тайм-аут 1 секунда
fmt.Println("Горутина работает слишком долго")
}
}


🟠Закрытие канала как индикатор завершения
Закрытие канала может служить сигналом того, что горутина завершила свою работу.
func worker(done chan struct{}) {
fmt.Println("Горутина работает...")
time.Sleep(2 * time.Second)
fmt.Println("Горутина завершена!")
close(done) // Закрываем канал
}

func main() {
done := make(chan struct{})

go worker(done)

// Проверяем, когда канал закроется
<-done
fmt.Println("Основной поток: горутина завершила работу")
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍4
🤔 В чём сложность удаления из начала внутри динамического массива (слайса) ?

Удаление из начала слайса требует сдвига всех оставшихся элементов на один шаг влево. Это операция линейной сложности — O(n), где n — количество элементов после удалённого.
В отличие от удаления с конца, которое обычно O(1), начало требует перераспределения памяти или сдвига указателей.


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

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

🚩Почему карты в Go не потокобезопасны

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

🟠Состояния гонки
Одновременный доступ к карте из нескольких горутин может привести к состояниям гонки, когда порядок выполнения операций непредсказуем.
🟠Паники
Одновременное изменение структуры карты, например добавление или удаление элементов, может вызвать панику в программе.

🚩Подходы к обеспечению потокобезопасности

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

import (
"fmt"
"sync"
)

func main() {
var mu sync.Mutex
m := make(map[string]int)
var wg sync.WaitGroup

write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}

read := func(key string) int {
mu.Lock()
defer mu.Unlock()
return m[key]
}

wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}


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

import (
"fmt"
"sync"
)

func main() {
var mu sync.RWMutex
m := make(map[string]int)
var wg sync.WaitGroup

write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}

read := func(key string) int {
mu.RLock()
defer mu.RUnlock()
return m[key]
}

wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}


🟠sync.Map
Go предоставляет специальную структуру sync.Map, которая изначально создана для безопасного использования в многопоточной среде. Она автоматически обеспечивает синхронизацию операций.
package main

import (
"fmt"
"sync"
)

func main() {
var m sync.Map
var wg sync.WaitGroup

wg.Add(2)
go func() {
defer wg.Done()
m.Store("key1", 42)
}()
go func() {
defer wg.Done()
value, _ := m.Load("key1")
fmt.Println(value)
}()
wg.Wait()
}


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

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

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

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

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

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

Синтаксис
slice = append(slice, elem1, elem2, ...)


Пример использования
package main

import "fmt"

func main() {
// Создаем слайс из 3 целых чисел
slice := []int{1, 2, 3}

// Добавляем один элемент
slice = append(slice, 4)

// Добавляем несколько элементов
slice = append(slice, 5, 6, 7)

// Выводим слайс
fmt.Println(slice) // Выводит: [1 2 3 4 5 6 7]
}


🚩Объяснение работы

1⃣Начальный слайс
Создаем слайс с тремя элементами [1, 2, 3].
slice := []int{1, 2, 3}   


2⃣Добавление одного элемента
Добавляем элемент 4 к слайсу. Теперь слайс содержит [1, 2, 3, 4].
slice = append(slice, 4)   


3⃣Добавление нескольких элементов
Добавляем элементы 5, 6, и 7. Теперь слайс содержит [1, 2, 3, 4, 5, 6, 7].
slice = append(slice, 5, 6, 7)   


4⃣Вывод слайса
Выводим слайс, который содержит [1, 2, 3, 4, 5, 6, 7].
fmt.Println(slice)   


Работа с емкостью и длиной
package main

import "fmt"

func main() {
slice := []int{1, 2, 3}
fmt.Printf("Before append: len=%d cap=%d %v\n", len(slice), cap(slice), slice)

slice = append(slice, 4)
fmt.Printf("After append: len=%d cap=%d %v\n", len(slice), cap(slice), slice)

slice = append(slice, 5, 6, 7)
fmt.Printf("After multiple appends: len=%d cap=%d %v\n", len(slice), cap(slice), slice)
}


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

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

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

Триггер — это специальная процедура в СУБД, которая автоматически выполняется при определённом событии (например, INSERT, UPDATE, DELETE) в таблице.

🚩Как работают триггеры?

Когда выполняется определённое действие с таблицей, триггер срабатывает автоматически и выполняет заданную логику. Это полезно для:
- Автоматической проверки данных.
- Поддержания целостности информации.
- Логирования изменений.

🚩Пример триггера в PostgreSQL

Допустим, у нас есть таблица orders, и мы хотим автоматически сохранять историю изменений заказов в таблицу orders_log.
CREATE TABLE orders_log (
id SERIAL PRIMARY KEY,
order_id INT,
old_status TEXT,
new_status TEXT,
changed_at TIMESTAMP DEFAULT now()
);

CREATE OR REPLACE FUNCTION log_order_update()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO orders_log (order_id, old_status, new_status)
VALUES (OLD.id, OLD.status, NEW.status);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER order_status_change
AFTER UPDATE ON orders
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION log_order_update();


🚩Разновидности триггеров

🟠До выполнения операции (`BEFORE`)
Используется для проверки или модификации данных перед изменением.

🟠После выполнения операции (`AFTER`)
Чаще всего используется для логирования или дополнительных действий.

🟠INSTEAD OF (для представлений)
Позволяет заменить выполнение операции (INSERT, UPDATE, DELETE).

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

Ключи должны быть сравнимыми типами, которые можно проверять на равенство.
1. Допустимые типы:
- Примитивы: int, float, string, bool.
- Указатели.
- Структуры, если все их поля имеют сравнимые типы.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Forwarded from easyoffer
Официальный релиз easyoffer 2.0 состоится уже в течение нескольких дней.

Напоминаю, что в честь релиза запускаем акцию.

Первые 500 покупателей получат:

🚀 Скидку 50% на PRO тариф на 1 год
🎁 Подарок ценностью 5000₽ для тех, кто подписан на этот канал

🔔 Подпишитесь на этот канал: https://t.me/+b2fZN17A9OQ3ZmJi
В нем мы опубликуем сообщение о релизе в первую очередь
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое тип rune Зачем их использовать?

Тип rune представляет собой alias для типа int32, предназначенного для хранения Unicode кодовых точек.

🚩Зачем он нужен?

🟠Работа с символами Unicode
Строки (string) являются последовательностями байтов, а не символов. Это означает, что один символ может занимать больше одного байта, особенно если это символ из расширенного набора Unicode.
Тип используется для работы с символами, представляемыми одной кодовой точкой Unicode. Это упрощает манипуляции с символами, так как каждая rune — это отдельный символ, независимо от его длины в байтах.

🟠Повышение читабельности кода
Использование типа rune делает код более понятным и само-документируемым. Когда в коде виден тип rune, это сразу указывает на то, что переменная предназначена для хранения одного символа, а не целого числа.

🚩Как его использовать ?

Создание и инициализация
      var r rune = '世'
fmt.Println(r) // Output: 19990


Итерация по строке
      s := "Привет, 世界"
for _, r := range s {
fmt.Printf("%c ", r)
}
// Output: П р и в е т , 世 界


Преобразование между string ито такое
      s := "Go"
runes := []rune(s)
fmt.Println(runes) // Output: [71 111]

s2 := string(runes)
fmt.Println(s2) // Output: Go


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

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

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

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

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

🟠Фиксированный размер
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
🟠Тип элементов
Все элементы массива имеют один и тот же тип.
🟠Непрерывное размещение в памяти
Элементы массива хранятся последовательно в памяти, что обеспечивает быстрый доступ к любому элементу по индексу.

🚩Объявление и инициализация массивов

Массивы объявляются с указанием типа элементов и фиксированного размера:
var arr [5]int


🟠Инициализация массива
Могут быть инициализированы при объявлении:
arr := [5]int{1, 2, 3, 4, 5}


Можно также инициализировать массив частично, оставив остальные элементы равными нулям:
arr := [5]int{1, 2}


🟠Доступ к элементам массива
Осуществляется с использованием индексов, начиная с 0:
fmt.Println(arr[0]) // 1
arr[1] = 10
fmt.Println(arr[1]) // 10


🟠Длина массива
Фиксирована и задается при его объявлении. Ее можно получить с помощью функции len:
fmt.Println(len(arr)) // 5


🟠Копирование массива
При присваивании одного массива другому копируются все элементы:
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := arr1
arr2[0] = 10
fmt.Println(arr1) // [1 2 3 4 5]
fmt.Println(arr2) // [10 2 3 4 5]


🟠Передача массива в функции
Копируется весь массив:
func modifyArray(a [5]int) {
a[0] = 10
}

arr := [5]int{1, 2, 3, 4, 5}
modifyArray(arr)
fmt.Println(arr) // [1 2 3 4 5]


🟠Сравнение массивов
С помощью оператора ==, если они имеют одинаковую длину и тип элементов:
arr1 := [3]int{1, 2, 3}
arr2 := [3]int{1, 2, 3}
arr3 := [3]int{4, 5, 6}

fmt.Println(arr1 == arr2) // true
fmt.Println(arr1 == arr3) // false


Пример
package main

import (
"fmt"
)

func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}

// Доступ к элементам
fmt.Println("First element:", arr[0]) // First element: 1

// Изменение элементов
arr[1] = 10
fmt.Println("Modified array:", arr) // Modified array: [1 10 3 4 5]

// Длина массива
fmt.Println("Length of array:", len(arr)) // Length of array: 5

// Копирование массива
arr2 := arr
arr2[0] = 20
fmt.Println("Original array:", arr) // Original array: [1 10 3 4 5]
fmt.Println("Copied array:", arr2) // Copied array: [20 10 3 4 5]

// Передача массива в функцию
modifyArray(arr)
fmt.Println("Array after modifyArray call:", arr) // Array after modifyArray call: [1 10 3 4 5]
}

func modifyArray(a [5]int) {
a[0] = 10
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие ключи могут быть в МАПе?

В map ключи должны быть сравнимыми, то есть поддерживать операцию сравнения ==. Это означает, что в качестве ключей можно использовать типы, такие как string, int, float, bool, array, pointer, struct (если все его поля сравнимы). Нельзя использовать slice, map, function в качестве ключей, так как они не поддерживают сравнение.

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

HTTP (HyperText Transfer Protocol) — это протокол, используемый для передачи данных в интернете.

🚩Основные версии HTTP.

🟠HTTP/0.9
Год выпуска: 1991

Особенности
Первая версия HTTP, очень простая. Поддерживала только GET-запросы. Отсутствие заголовков, только один объект мог быть передан в ответ на запрос.

Использование:
В настоящее время практически не используется.

🟠HTTP/1.0
Год выпуска: 1996

Особенности
Введены методы запроса, такие как GET, POST и HEAD. Поддержка заголовков для метаданных. Каждый запрос/ответ требует нового соединения, что делает передачу данных менее эффективной.

Использование
Исторически важен, но также почти не используется в современных приложениях.

🟠HTTP/1.1
Год выпуска: 1997

Особенности
Поддержка устойчивых (persistent) соединений, что позволяет повторное использование одного соединения для нескольких запросов/ответов. Введены дополнительные методы запросов, такие как OPTIONS, PUT, DELETE, TRACE и CONNECT. Поддержка chuncked transfer encoding для передачи данных по частям. Улучшена работа с кэшированием и аутентификацией.

Использование
Широко используется и в настоящее время, хотя многие системы переходят на HTTP/2.

🟠HTTP/2
Год выпуска: 2015

Особенности
Бинарный протокол, что улучшает производительность и уменьшает количество ошибок. Поддержка мультиплексирования, что позволяет отправлять несколько запросов через одно соединение одновременно, уменьшая задержки. Сжатие заголовков, что уменьшает объем передаваемых данных. Серверное push-сообщение (server push), позволяющее серверу отправлять данные клиенту до того, как он их запросит.

Использование
Быстро набирает популярность благодаря улучшенной производительности и эффективности.

🟠HTTP/3
Год выпуска: 2022 (черновая версия в 2020)

Особенности
Основан на протоколе QUIC, который работает поверх UDP, а не TCP. Поддержка улучшенного мультиплексирования и быстрого установления соединений. Лучшая устойчивость к потерям пакетов и более высокая скорость передачи данных по сравнению с HTTP/2.

Использование
Внедрение продолжается, но многие крупные интернет-компании, такие как Google и Facebook, уже активно используют HTTP/3.

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

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


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