Golang | Вопросы собесов
4.33K subscribers
28 photos
698 links
Download Telegram
🤔 Что такое интеграционные тесты?

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

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

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

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

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

🚩Как их писать?

Интеграционные тесты могут требовать наличия нескольких зависимостей, таких как база данных, внешние API или другие сервисы. Настройте тестовую среду, которая будет эмулировать реальную среду.
      // main.go
package main

import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"log"
)

type User struct {
ID int
Name string
}

func CreateUser(db *sql.DB, name string) (int, error) {
res, err := db.Exec("INSERT INTO users(name) VALUES(?)", name)
if err != nil {
return 0, err
}
id, err := res.LastInsertId()
if err != nil {
return 0, err
}
return int(id), nil
}

func GetUser(db *sql.DB, id int) (User, error) {
var user User
err := db.QueryRow("SELECT id, name FROM users WHERE id = ?", id).Scan(&user.ID, &user.Name)
if err != nil {
return user, err
}
return user, nil
}

func main() {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()

_, err = db.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
if err != nil {
log.Fatal(err)
}
}
// main_test.go
package main

import (
"database/sql"
"testing"
_ "github.com/mattn/go-sqlite3"
)

func setupTestDB(t *testing.T) *sql.DB {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatal(err)
}
_, err = db.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
if err != nil {
t.Fatal(err)
}
return db
}

func TestCreateAndGetUser(t *testing.T) {
db := setupTestDB(t)
defer db.Close()

// Создание пользователя
userID, err := CreateUser(db, "John Doe")
if err != nil {
t.Fatalf("Failed to create user: %v", err)
}

// Получение пользователя
user, err := GetUser(db, userID)
if err != nil {
t.Fatalf("Failed to get user: %v", err)
}

// Проверка результатов
if user.Name != "John Doe" {
t.Errorf("Expected name to be 'John Doe', got %s", user.Name)
}
}


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

Функция copy копирует элементы из одного слайса в другой.
1. Синтаксис: copy(dst, src).
2. Копируется минимальное количество элементов, равное длине меньшего слайса.


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

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

🚩Мультиплексирование

🟠HTTP/1.1
Поддерживает одновременное открытие нескольких TCP соединений (обычно 6-8), что позволяет загружать несколько ресурсов параллельно. Однако каждое соединение может обрабатывать только один запрос за раз, что приводит к задержкам из-за блокировки очереди (head-of-line blocking).

🟠HTTP/2
Вводит мультиплексирование, позволяющее отправлять множество запросов и ответов асинхронно через одно единственное TCP соединение. Это значительно уменьшает задержки и улучшает производительность при загрузке страниц с большим количеством ресурсов.

🚩Бинарный протокол

🟠HTTP/1.1
Является текстовым протоколом, что означает, что запросы и ответы форматируются в виде читаемого текста.

🟠HTTP/2
Бинарный протокол, который делает передачу данных более эффективной и менее подверженной ошибкам в синтаксическом анализе. Бинарный формат упрощает реализацию парсеров и уменьшает размер передаваемых данных.

🚩Сжатие заголовков

🟠HTTP/1.1
Заголовки передаются без сжатия, что может привести к значительному объему передаваемых данных, особенно если одни и те же заголовки отправляются повторно с каждым запросом.

🟠HTTP/2
Использует механизм сжатия заголовков HPACK, который уменьшает избыточность заголовков, сжимая их перед отправкой. Это особенно эффективно для повторяющихся запросов к одним и тем же серверам.

🚩Приоритизация запросов

🟠HTTP/1.1
Не поддерживает приоритизацию запросов, из-за чего браузеры должны использовать эвристики для управления приоритетами ресурсов.

🟠HTTP/2
Поддерживает явную приоритизацию запросов, позволяя клиенту указывать приоритет обработки ресурсов, что делает загрузку страниц более эффективной.

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

Агрегатные функции работают с группами данных и возвращают один результат:
- COUNT() — количество.
- SUM() — сумма.
- AVG() — среднее.
- MIN(), MAX() — минимум и максимум.
- В некоторых СУБД есть STRING_AGG(), GROUP_CONCAT() — объединение строк.
Они часто используются с GROUP BY в SQL и при анализе данных.


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

Синхронизация необходима для предотвращения конфликтов при одновременном доступе из нескольких потоков (или горутин). Без синхронизации возможны:
- Повреждение данных
- Гонки (data race)
- Непредсказуемое поведение и ошибки
Примитивы синхронизации (mutex, atomic и т.д.) обеспечивают корректность и согласованность данных.


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

Go — это императивный язык программирования.

🚩Почему Go императивный?

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

import "fmt"

func main() {
sum := 0
for i := 1; i <= 5; i++ {
sum += i // Явно изменяем переменную sum
}
fmt.Println("Сумма:", sum)
}


🚩Декларативные элементы в Go

Хотя Go — это в первую очередь императивный язык, в нем есть элементы декларативного подхода. Например:
🟠Функциональные элементы
map, filter через срезы и функции высшего порядка.
🟠Структурированность кода
интерфейсы позволяют писать код, в котором детали реализации скрыты (инкапсуляция).
🟠Go concurrency (goroutines, channels)
вместо явного управления потоками, мы декларируем взаимодействие через каналы.

package main

import "fmt"

func mapSlice(slice []int, f func(int) int) []int {
result := make([]int, len(slice))
for i, v := range slice {
result[i] = f(v) // Декларативное применение функции к элементам
}
return result
}

func main() {
nums := []int{1, 2, 3, 4, 5}
squared := mapSlice(nums, func(n int) int { return n * n })
fmt.Println(squared) // [1 4 9 16 25]
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 В какой момент инициализированное значение переменной передается в defer, как это связано с именованием функции?

Значения, передаваемые в defer, фиксируются в момент объявления defer, а не в момент выполнения.
Если ты передаёшь результат выражения, он вычисляется сразу, а отложенный вызов запоминает результат.
Но если используется именованная возвращаемая переменная, и она изменяется внутри defer, то её новое значение попадает в результат. Это позволяет, например, изменить результат функции прямо из defer-блока.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
🤔 В чем разница слайсов и массивов?

Массивы в Go имеют фиксированную длину и содержат элементы одного типа, тогда как слайсы — динамические структуры, которые могут изменять свою длину. Слайсы являются ссылочными типами и указывают на массив, предоставляя часть или весь массив. При добавлении новых элементов слайс автоматически расширяет свой размер. Массивы редко используются напрямую из-за своей фиксированной длины, в отличие от слайсов, которые более гибкие.

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

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

🚩Чтобы избежать deadlock, нужно следовать этим принципам

🟠Грамотно проектировать порядок блокировок
Если несколько горутин используют блокировки (например, через мьютексы), убедитесь, что все они захватывают их в одном и том же порядке.
func main() {
var mu1, mu2 sync.Mutex

go func() {
mu1.Lock()
defer mu1.Unlock()

mu2.Lock()
defer mu2.Unlock()
}()

go func() {
mu2.Lock()
defer mu2.Unlock()

mu1.Lock()
defer mu1.Unlock()
}()
}


🟠Не блокировать каналы навсегда
Каналы должны всегда иметь возможность отправки и получения данных. Если одна сторона (отправитель или получатель) заблокирована навсегда, возникает deadlock.
func main() {
ch := make(chan int)
ch <- 42 // Deadlock, так как никто не читает из канала
}


🟠Закрывайте каналы правильно
Каналы нужно закрывать только со стороны отправителя, и только тогда, когда больше не будет отправок данных. Неправильное закрытие или отсутствие закрытия может привести к проблемам, включая deadlock.
ch := make(chan int)
close(ch) // Закрыт слишком рано
ch <- 42 // Паника


🟠Избегайте ситуаций с ожиданием себя
Иногда deadlock происходит, если горутина ждет сама себя.
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch) // Никогда не выполнится
}


🟠Использовать тайм-ауты и селекторы
Go позволяет избегать блокировок с помощью механизма тайм-аутов и оператора select. Если операция занимает слишком много времени, можно выполнить альтернативное действие.
func main() {
ch := make(chan int)

select {
case data := <-ch:
fmt.Println("Получены данные:", data)
case <-time.After(1 * time.Second):
fmt.Println("Тайм-аут, завершение")
}
}


🟠Используйте инструменты анализа
Go предоставляет утилиту go run -race, которая помогает выявлять гонки данных и другие проблемы, связанные с синхронизацией.
go run -race main.go


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

1. Горутина ждет данные, а никто не пишет в канал (<-chan, но нет chan <-).
2. Основная горутина завершилась, а другие ждут завершения.
3. Все горутины заблокированы на ожидании данных (select { case <-ch1: case <-ch2: } – если ни один не отправляет данные).
4. Закрыли канал, но кто-то пытается в него записать – вызывает panic.


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

В Go эффективное объединение строк – важная задача, поскольку строки неизменяемые. Неправильный подход (например, простая конкатенация s1 + s2 + s3) может привести к множественным аллокациям памяти и копированиям.

🚩Способы объединения строк

Использование strings.Builder (Рекомендуется)
Это самый эффективный способ склеивания строк, так как он минимизирует количество аллокаций.
package main

import (
"fmt"
"strings"
)

func main() {
var sb strings.Builder

sb.WriteString("Hello")
sb.WriteString(", ")
sb.WriteString("World!")

result := sb.String()
fmt.Println(result) // Hello, World!
}


Использование + (Неэффективно )
s := "Hello" + ", " + "World!"


Использование fmt.Sprintf (Неэффективно )
s := fmt.Sprintf("%s, %s!", "Hello", "World")


Использование strings.Join (Хорошо для срезов )
Если строки хранятся в []string, strings.Join – это оптимальный вариант
package main

import (
"fmt"
"strings"
)

func main() {
words := []string{"Hello", "World", "Go"}
result := strings.Join(words, ", ")
fmt.Println(result) // Hello, World, Go
}


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

Это состояние, при котором все горутины ожидают события, которое не наступит. Go детектирует deadlock и вызывает panic, если основная горутина заблокирована на ожидании данных из канала, но нет активных писателей.


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

Mutex (от Mutual Exclusion — взаимное исключение) — это примитив синхронизации, который используется для защиты критических секций ресурса или данных, доступ к которым должен быть ограничен таким образом, чтобы только один поток или горутина могли работать с ним в каждый конкретный момент времени. Mutex гарантирует, что только один поток может входить в защищённую секцию кода, выполняющую операции над общими данными.

🚩Какие бывают Mutex

🟠Блокирующие Mutex (Blocking Mutexes)
Это наиболее распространённый тип мьютексов. При попытке захватить мьютекс, если он уже занят другим потоком, поток блокируется и ожидает, пока мьютекс не будет освобождён.

🟠Неблокирующие Mutex (Non-blocking or Spinlocks)
Вместо блокирования потока, потоки активно проверяют состояние мьютекса в цикле. Это может быть эффективно, если мьютекс захватывается на очень короткое время, так как избегается затрата времени на блокировку и разблокировку потока.

🚩Использование Mutex

Стандартная библиотека предоставляет мьютекс в пакете sync. Вот пример того, как можно использовать мьютекс для синхронизации доступа к общему ресурсу:
package main

import (
"fmt"
"sync"
)

var (
balance int
mutex sync.Mutex
)

func deposit(value int, wg *sync.WaitGroup) {
mutex.Lock() // Захват мьютекса перед изменением переменной balance
fmt.Printf("Depositing %d to account with balance: %d\n", value, balance)
balance += value
mutex.Unlock() // Освобождение мьютекса после изменения
wg.Done()
}

func main() {
var wg sync.WaitGroup
wg.Add(2)
go deposit(100, &wg)
go deposit(200, &wg)
wg.Wait()
fmt.Printf("New Balance %d\n", balance)
}


🚩Рекомендации по использованию

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

🟠Избегайте вложенных мьютексов
Это может привести к взаимоблокировкам, если мьютексы захватываются в разном порядке.

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

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

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

Горутины управляются Go runtime, а не операционной системой напрямую.
Это делает их лёгкими и дешевыми — можно создавать тысячи горутин без нагрузки на систему.
ОС видит лишь ограниченное количество потоков (M), а Go сам планирует, какие G выполнять на каких M через P.


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

Слайс (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
🤔 Что такое указатели?

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

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

В Go пустой интерфейс interface{} является особым типом, который может содержать значение любого типа. Это связано с тем, что в Go любой тип реализует пустой интерфейс, поскольку в нем нет методов, которые нужно реализовать.

🚩Пустой интерфейс

Поскольку пустой интерфейс не требует реализации каких-либо методов, любой тип в Go автоматически реализует этот интерфейс. Это делает пустой интерфейс универсальным контейнером для значений любых типов.
type interface{} interface {}


🚩Внутреннее представление интерфейсов в Go

🟠Type
Типа конкретного значения
🟠Value
Самого значения

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

🚩Приведение пустого интерфейса к конкретному типу

Когда значение из пустого интерфейса приводится к конкретному типу, происходит проверка типа во время выполнения. Если значение внутри интерфейса действительно является указанным типом, приведение успешно. В противном случае приведение не удается, и возвращается значение nil или происходит паника, если приведение выполнено без проверки.

Присваивание значений пустому интерфейсу
package main

import "fmt"

func main() {
var i interface{}
i = 42
fmt.Println(i) // 42

i = "hello"
fmt.Println(i) // hello
}


Утверждение типа (Type Assertion)
package main

import "fmt"

func main() {
var i interface{} = "hello"

// Утверждение типа с проверкой
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
} else {
fmt.Println("Not a string")
}

// Утверждение типа без проверки
// Это вызовет панику, если тип не соответствует
s = i.(string)
fmt.Println("String:", s)
}


Использование switch для проверки типа
package main

import "fmt"

func printType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Println("String:", v)
case int:
fmt.Println("Integer:", v)
case bool:
fmt.Println("Boolean:", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}

func main() {
printType("hello")
printType(42)
printType(true)
printType(3.14)
}


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

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN 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