Golang | Вопросы собесов
4.7K subscribers
37 photos
959 links
Download Telegram
🤔 Возможен ли JOIN со вложенными запросами?

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

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

JOIN можно использовать не только с реальными таблицами, но и с результатами подзапросов, если они представляют собой временные таблицы.

🚩Пример: JOIN с подзапросом

Допустим, у нас есть две таблицы:
- orders (id, user_id, total)
- users (id, name)
Мы хотим получить всех пользователей и их заказы, но только те заказы, где сумма больше 100
SELECT u.name, sub.total
FROM users u
JOIN (
SELECT user_id, total
FROM orders
WHERE total > 100
) AS sub ON u.id = sub.user_id;


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

NAT может использоваться для реализации прокси-серверов или маршрутизации сетевых запросов с помощью библиотек вроде net или net/http. Позволяет взаимодействовать с NAT, включая обработку частных и публичных IP-адресов.


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

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

🚩Причины

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

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

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

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

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

🟠Улучшение качества кода
Постоянное написание тестов и их прохождение помогает поддерживать высокое качество кода. Тесты выявляют дефекты на ранних стадиях разработки и обеспечивают, что новые изменения не нарушают существующую функциональность.

🚩Пример процесса TDD

1⃣Написание теста
package main

import "testing"

func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Expected 5, but got %d", result)
}
}


2⃣Запуск теста
На этом этапе тест не пройдет, так как функция Add еще не реализована.

3⃣Реализация кода
package main

func Add(a, b int) int {
return a + b
}


4⃣Запуск теста снова
Теперь тест пройдет, так как функция Add реализована корректно.

5⃣Рефакторинг
При необходимости выполняется рефакторинг кода для улучшения его структуры, при этом тесты продолжают проходить, что гарантирует сохранение функциональности.

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

1. Структуры:
- Структуры заменяют классы и служат для хранения данных.
2. Методы:
- Методы определяются отдельно и привязываются к структурам.
3. Интерфейсы:
- Полиморфизм реализуется через интерфейсы, задающие набор методов.
4. Встраивание:
- Структуры могут встраивать другие структуры для наследования поведения.


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

SSL (Secure Sockets Layer) — это протокол, который обеспечивает безопасность передачи данных в интернете, используя шифрование. Он был разработан для защиты данных, передаваемых между клиентом (например, веб-браузером) и сервером (например, веб-сайтом), от перехвата и манипуляций.

🚩Основные функции

🟠Шифрование:
Защита данных от перехвата и чтения посторонними лицами путем их шифрования.
🟠Аутентификация:
Подтверждение подлинности сервера (и иногда клиента) с помощью цифровых сертификатов, что позволяет клиенту убедиться, что он подключен к настоящему серверу.
🟠Целостность данных:
Проверка того, что данные не были изменены во время передачи, с помощью контрольных сумм и хеш-функций.

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

1⃣Установка соединения:
Клиент инициирует соединение с сервером, запрашивая защищенное соединение.
2⃣Передача сертификата:
Сервер отправляет свой цифровой сертификат, который содержит его публичный ключ и информацию о сервере.
3⃣Проверка сертификата:
Клиент проверяет сертификат, используя доверенные центры сертификации (CA), чтобы удостовериться в подлинности сервера.
4⃣Создание сессионных ключей:
Клиент и сервер используют асимметричное шифрование для обмена ключами сеанса, которые затем используются для симметричного шифрования данных в течение сессии.
5⃣Шифрование данных:
Все данные, передаваемые между клиентом и сервером, шифруются с использованием симметричных ключей, обеспечивая безопасность передачи.

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

При посещении веб-сайта с использованием HTTPS (например, https://example.com), SSL обеспечивает шифрование и безопасность данных, передаваемых между вашим браузером и сервером.

🚩Развитие

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

🚩TLS как наследник SSL

🟠TLS (Transport Layer Security):
SSL был заменен протоколом TLS, который является его преемником и предлагает улучшенную безопасность. Текущие версии TLS (1.2 и 1.3) используются вместо SSL.
🟠Основные отличия:
TLS обеспечивает более сильное шифрование, лучшее управление сессионными ключами и устранение уязвимостей, найденных в SSL.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤔1
🤔 В чем отличия HTTP и HTTPS?

HTTP (HyperText Transfer Protocol) — это протокол передачи данных, который используется для загрузки веб-страниц. HTTPS (HTTP Secure) — это расширенная версия HTTP, которая добавляет слой шифрования (SSL/TLS), обеспечивая защиту передаваемых данных от прослушивания, перехвата и изменения посторонними. HTTPS необходим для защиты конфиденциальности и безопасности пользовательских данных.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Как ООП в 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
👍1
🤔 Зачем нужны таймауты при HTTP-запросах?

Таймауты:
- Ограничивают время ожидания ответа, чтобы не зависать навечно.
- Защищают от зависших серверов или сетевых проблем.
- Позволяют освободить ресурсы в клиентском приложении.
- Повышают надёжность: без таймаутов приложение может «подвисать» или блокировать выполнение других операций.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
👍1
🤔 Что такое пустой интерфейс?

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


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

В многопоточных (параллельных) программах горутины (goroutines) могут одновременно изменять одни и те же данные. Если не синхронизировать доступ, это приведёт к гонке данных (data race), когда несколько потоков читают/пишут одно и то же значение одновременно.

🚩`sync.Mutex` (мьютексы — блокировка данных)

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

import (
"fmt"
"sync"
)

var (
counter int
mutex sync.Mutex
)

func increment(wg *sync.WaitGroup) {
defer wg.Done()
mutex.Lock() // Блокируем доступ
counter++ // Изменяем данные
mutex.Unlock() // Разблокируем доступ
}

func main() {
var wg sync.WaitGroup

for i := 0; i < 1000; i++ {
wg.Add(1)
go increment(&wg)
}

wg.Wait()
fmt.Println("Итоговый счетчик:", counter) // 1000
}


🚩`sync.RWMutex` (разделяемая блокировка)

Позволяет нескольким горутинам читать данные одновременно, но блокирует запись.
var (
data int
mutex sync.RWMutex
)

func readData(wg *sync.WaitGroup) {
defer wg.Done()
mutex.RLock() // Разрешаем чтение
fmt.Println("Читаем данные:", data)
mutex.RUnlock()
}

func writeData(wg *sync.WaitGroup) {
defer wg.Done()
mutex.Lock() // Блокируем на запись
data++
mutex.Unlock()
}


🚩`sync.WaitGroup` (ожидание горутин)

Позволяет дождаться завершения всех горутин без блокировки данных.
var wg sync.WaitGroup

wg.Add(2) // Ожидаем 2 горутины
go func() {
defer wg.Done()
fmt.Println("Горутина 1 завершилась")
}()
go func() {
defer wg.Done()
fmt.Println("Горутина 2 завершилась")
}()

wg.Wait() // Ждём завершения всех горутин
fmt.Println("Все горутины завершены")


🚩`sync/atomic` (атомарные операции)

Атомарные операции быстрее мьютексов и гарантируют безопасное обновление переменных без гонок данных.
import "sync/atomic"

var counter int64

func incrementAtomic() {
atomic.AddInt64(&counter, 1) // Атомарное увеличение
}


🚩Каналы (лучший способ в Go)

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

import "fmt"

func main() {
ch := make(chan int) // Канал для передачи данных

go func() {
ch <- 42 // Отправляем данные
}()

data := <-ch // Получаем данные
fmt.Println("Получено:", data)
}


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

Хэш-коллизия возникает, когда два разных ключа имеют одинаковое хэш-значение. Это проблема, так как Map должен хранить уникальные ключи. Для её разрешения используются методы, такие как цепочки (chaining) или открытая адресация (open addressing).

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

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

🚩Получение значений

🟠Простое получение значения по ключу
Для этого используется синтаксис индексирования
value := myMap[key]


Пример
package main

import "fmt"

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

value := myMap["Alice"]
fmt.Println("Alice:", value) // Alice: 25
}


🟠Проверка существования ключа
Для этого используется синтаксис двойного присваивания
value, exists := myMap[key]


Пример
package main

import "fmt"

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

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


🚩Запись значений

🟠Добавление или обновление значения
Для этого используется синтаксис индексирования:
myMap[key] = value


Пример
package main

import "fmt"

func main() {
myMap := map[string]int{}

// Добавление значений
myMap["Alice"] = 25
myMap["Bob"] = 30

fmt.Println("Map:", myMap) // Map: map[Alice:25 Bob:30]

// Обновление значения
myMap["Alice"] = 26
fmt.Println("Updated Map:", myMap) // Updated Map: map[Alice:26 Bob:30]
}


🟠Удаление значений из карты
Для этого используется встроенная функция delete:
delete(myMap, key)


Пример
package main

import "fmt"

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

// Удаление значения по ключу
delete(myMap, "Alice")
fmt.Println("Map after deletion:", myMap) // Map after deletion: map[Bob:30]
}


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

🟠Отсутствие ключа
Если ключ отсутствует в карте, при попытке получения значения будет возвращено нулевое значение типа значения карты. Например, для карты map[string]int это будет 0.
        package main

import "fmt"

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

value := myMap["Bob"] // Ключ "Bob" отсутствует
fmt.Println("Value:", value) // Value: 0
}


🟠Запись в неинициализированную карту
Нельзя записывать значения в nil карту. Это приведет к панике времени выполнения.
        package main

func main() {
var myMap map[string]int // nil карта
myMap["Alice"] = 25 // Вызовет панику: runtime error: assignment to entry in nil map
}


🟠Итерация по карте
Порядок итерации по карте не определен и может различаться между разными запусками программы.
        package main

import "fmt"

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

for key, value := range myMap {
fmt.Printf("%s: %d\n", key, value)
}
}


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

rune — это псевдоним для int32, который представляет один символ Unicode. Используется для работы с многоязычными текстами и символами, особенно когда требуется обработка не-ASCII символов. Это полезно в случаях, когда нужно обрабатывать строки на уровне символов, а не байтов.

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

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

🟠Управление временем выполнения операций
Контексты позволяют задавать дедлайны и таймауты для операций.
context.WithTimeout создает контекст с таймаутом, после которого операция будет автоматически отменена.
ctx, cancel := context.WithTimeout(parentCtx, 2*time.Second)
defer cancel()


context.WithDeadline создает контекст с дедлайном, который определяет точное время, после которого операция будет отменена.
deadline := time.Now().Add(5 * time.Second)
ctx, cancel := context.WithDeadline(parentCtx, deadline)
defer cancel()


🟠Явная отмена операций
Контексты позволяют явно отменять операции, что полезно для управления горутинами и предотвращения утечек памяти.
context.WithCancel создает контекст, который может быть отменен вручную с помощью функции cancel.
ctx, cancel := context.WithCancel(parentCtx)
defer cancel()


🟠Передача метаданных
Контексты позволяют передавать данные между функциями, что полезно для передачи информации о запросах, пользователей и других данных.
context.WithValue создает контекст, который содержит пару ключ-значение для передачи метаданных.
type key string
ctx := context.WithValue(parentCtx, key("userID"), 12345)


🟠Вложенные контексты
Можно создавать иерархии контекстов, где каждый дочерний контекст наследует отмену и дедлайны от родительского.
Создание вложенных контекстов позволяет строить гибкие и сложные системы управления временем выполнения и отмены.
ctx1, cancel1 := context.WithCancel(parentCtx)
ctx2, cancel2 := context.WithTimeout(ctx1, 1*time.Second)
defer cancel1()
defer cancel2()


🟠Синхронизация горутин
Контексты обеспечивают механизм для синхронизации и координации работы нескольких горутин.
Пример синхронизации горутин
var wg sync.WaitGroup
ctx, cancel := context.WithCancel(parentCtx)
defer cancel()

wg.Add(2)
go func() {
defer wg.Done()
worker(ctx, "Worker 1")
}()
go func() {
defer wg.Done()
worker(ctx, "Worker 2")
}()
wg.Wait()

func worker(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "stopped")
return
default:
fmt.Println(name, "working")
time.Sleep(1 * time.Second)
}
}
}


🟠Управление жизненным циклом запросов
Контексты широко используются в веб-серверах для управления жизненным циклом HTTP-запросов, обеспечивая таймауты и отмену при завершении обработки запросов.
Пример использования контекста в обработчике HTTP-запроса
func handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
select {
case <-time.After(5 * time.Second):
fmt.Fprintln(w, "Request processed")
case <-ctx.Done():
err := ctx.Err()
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}

http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)


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

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

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

Слайс (slice) — это динамический массив, который ссылается на часть массива в памяти. В отличие от массивов (array), слайсы могут изменять размер.

🚩Внутреннее устройство слайса

Слайс в Go — это структура
type SliceHeader struct {
Data uintptr // Указатель на массив в памяти
Len int // Длина слайса (количество элементов)
Cap int // Вместимость (capacity) — сколько элементов может вместить без перевыделения памяти
}


Пример структуры слайса
arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4] // Берём срез от 2-го до 4-го элемента
fmt.Println(s) // [2 3 4]


🚩Создание слайсов

Есть несколько способов создать слайс:
Способ 1: Срез массива
arr := [5]int{10, 20, 30, 40, 50}
s := arr[1:4] // [20 30 40]


Способ 2: Использование make()
s := make([]int, 3, 5) // Длина 3, вместимость 5
fmt.Println(s, len(s), cap(s)) // [0 0 0] 3 5


Способ 3: Литерал (инициализация значениями)
s := []int{1, 2, 3}
fmt.Println(s) // [1 2 3]


🚩Изменение слайса

Слайсы можно изменять, используя append().
s := []int{1, 2, 3}
s = append(s, 4, 5)
fmt.Println(s) // [1 2 3 4 5]


🚩Как растёт `slice`?

Когда append() увеличивает slice, Go использует оптимизированный алгоритм роста:
- Если cap < 1024, слайс удваивает размер (cap *= 2).
- Если cap >= 1024, рост идёт примерно на 25% (cap += cap / 4).
s := []int{}
for i := 0; i < 10; i++ {
s = append(s, i)
fmt.Printf("Len: %d, Cap: %d\n", len(s), cap(s))
}


Выход (пример)
Len: 1, Cap: 1
Len: 2, Cap: 2
Len: 3, Cap: 4
Len: 5, Cap: 8
Len: 9, Cap: 16


🚩Как избежать неожиданных эффектов?

Так как слайсы хранят ссылку на массив, возможны побочные эффекты.
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[:3] // [1 2 3]
s2 := arr[2:] // [3 4 5]
s2[0] = 100 // Меняем первый элемент s2

fmt.Println(s1) // [1 2 100] ❗️ s1 тоже изменился


Решение: используйте copy() для создания нового массива.
s1 := []int{1, 2, 3}
s2 := make([]int, len(s1))
copy(s2, s1) // Копируем данные
s2[0] = 100
fmt.Println(s1) // [1 2 3] Оригинал не изменился


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
🤔 Как можно обработать панику с помощью defer и recover?

При возникновении паники функция defer откладывает выполнение восстановления до выхода из текущей функции, а recover перехватывает ошибку, предотвращая завершение программы. Это полезно для логирования ошибок и безопасного завершения работы.


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

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

🚩Свойства ключей

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

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

🚩Допустимые типы ключей

Булевый тип (bool)
  m := map[bool]string{
true: "Yes",
false: "No",
}


Целочисленные типы (int, int8, int16, int32, int64, а также их беззнаковые эквиваленты uint, uint8, uint16, uint32, uint64)
  m := map[int]string{
1: "One",
2: "Two",
}


Числа с плавающей точкой (float32, float64)
  m := map[float64]string{
1.1: "One point one",
2.2: "Two point two",
}


Строки (string)
  m := map[string]int{
"Alice": 25,
"Bob": 30,
}


Составные типы (структуры, массивы), при условии, что все их поля также поддерживают сравнение с помощью оператора ==
  type Key struct {
FirstName string
LastName string
}

m := map[Key]int{
{"Alice", "Smith"}: 1,
{"Bob", "Johnson"}: 2,
}


🚩Недопустимые типы ключей

🟠Срезы (slice)
Срезы не поддерживают операцию сравнения с использованием оператора == (только сравнение с nil).
🟠Карты (map)
Карты не поддерживают операцию сравнения.
🟠Функции (func)
Функции не поддерживают операцию сравнения.

package main

import "fmt"

type Person struct {
FirstName string
LastName string
}

func main() {
// Создаем карту с ключами типа Person
m := make(map[Person]int)

// Вставляем значения в карту
m[Person{"Alice", "Smith"}] = 25
m[Person{"Bob", "Johnson"}] = 30

// Выводим значения из карты
fmt.Println(m[Person{"Alice", "Smith"}]) // Выводит: 25
fmt.Println(m[Person{"Bob", "Johnson"}]) // Выводит: 30
}


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

1. Мьютексы для блокировки критических секций.
2. Каналы для организации потокобезопасного взаимодействия.
3. WaitGroup для ожидания завершения нескольких горутин.
4. Атомарные операции для управления простыми данными.


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