package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("деление на ноль")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Ошибка:", err)
} else {
fmt.Println("Результат:", result)
}
}
package main
import "fmt"
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Поймана ошибка:", r)
}
}()
fmt.Println("Выполняется riskyFunction...")
panic("Что-то пошло не так!")
fmt.Println("Этот код не будет выполнен")
}
func main() {
fmt.Println("Начало программы")
riskyFunction()
fmt.Println("Конец программы")
}
Механизмы panic и recover следует использовать только в следующих случаях:
Please open Telegram to view this post
VIEW IN TELEGRAM
🤩31🎉24❤19🔥14👍8🥰8👏2
🎯 С завтрашнего дня в канале запускается ежедневная викторина по Golang и базам данных.
Каждый день в канале будут публиковаться опросы по Go и базам данных. После этого в течение дня в ответ на опрос будет появляться пост с подробным разбором темы, чтобы вы могли глубже разобраться в вопросе.
💡 Это отличный способ не только проверить свои знания, но и получить развёрнутое понимание по каждой теме. До завтра!
Каждый день в канале будут публиковаться опросы по Go и базам данных. После этого в течение дня в ответ на опрос будет появляться пост с подробным разбором темы, чтобы вы могли глубже разобраться в вопросе.
💡 Это отличный способ не только проверить свои знания, но и получить развёрнутое понимание по каждой теме. До завтра!
👍35🎉26🤩24🔥14🥰12❤5👏1
День 1️⃣
Сегодня обсудим две важные темы: интерфейсы в Go и команду EXPLAIN ANALYZE в Postgres.
Поехали! 🚀
Сегодня обсудим две важные темы: интерфейсы в Go и команду EXPLAIN ANALYZE в Postgres.
Поехали! 🚀
🤩37🎉28👍13❤2🔥2
❓ Вопрос: Что происходит, когда интерфейс в Go сравнивается с nil?
Anonymous Quiz
32%
Сравнение всегда возвращает true, если интерфейс не был инициализирован
29%
Сравнение возвращает true, только если и тип, и значение интерфейса равны nil
9%
Сравнение возвращает true, если значение интерфейса равно nil, независимо от типа
29%
Сравнение всегда возвращает false, так как интерфейсы нельзя сравнивать с nil
👍43🔥37🎉29❤10🤩7
Рунет умер, но вы держитесь. А у вас как дела?
👍 — да, тоже всё упало
⚡️ — нет, всё работает
👍 — да, тоже всё упало
⚡️ — нет, всё работает
👍47🤩18🎉16❤12🥰6🔥5⚡1👏1
Рунет ожил! Техдолга по сегодняшним постам не будет 🎉
Если у вас тоже всё вернулось в норму, ставьте 👍
Если у вас тоже всё вернулось в норму, ставьте 👍
👍51🤩30🔥20🎉19❤5
Нияз Хадимуллин | Ментор по GO
❓ Вопрос: Что происходит, когда интерфейс в Go сравнивается с nil?
Итак, уважаемые знатоки, внимание, вопрос... Что происходит, когда интерфейс в Go сравнивается с nil?
📊 Лишь 25% проголосовавших в опросе выбрали верный вариант!
⁉️ Правильный ответ: Сравнение возвращает true, только если и тип, и значение интерфейса равны nil.
💡 Почему так?
Интерфейс в Go — это структура, которая состоит из двух компонентов:
1. Указатель на тип (type): Содержит информацию о типе данных, который реализует интерфейс. Например, *MyStruct.
2. Указатель на значение (value): Содержит конкретное значение этого типа. Например, указатель на структуру или nil.
‼️ Таким образом, когда вы сравниваете интерфейс с nil, Go проверяет оба компонента и, если хотя бы один из них не равен nil, интерфейс не считается nil.
📊 Лишь 25% проголосовавших в опросе выбрали верный вариант!
💡 Почему так?
Интерфейс в Go — это структура, которая состоит из двух компонентов:
1. Указатель на тип (type): Содержит информацию о типе данных, который реализует интерфейс. Например, *MyStruct.
2. Указатель на значение (value): Содержит конкретное значение этого типа. Например, указатель на структуру или nil.
package main
import "fmt"
type MyInterface interface {
Method()
}
type MyStruct struct{}
func (m *MyStruct) Method() {
fmt.Println("Oh, hi, Mark!")
}
func main() {
var i MyInterface // интерфейс не инициализирован, поэтому его тип и значение равны nil
fmt.Println(i == nil) // true
var s *MyStruct = nil // указатель на структуру равен nil
i = s // интерфейс содержит тип *MyStruct, значение nil
fmt.Println(i == nil) // false
}
‼️ Таким образом, когда вы сравниваете интерфейс с nil, Go проверяет оба компонента и, если хотя бы один из них не равен nil, интерфейс не считается nil.
👍39🎉26🤩22🔥10❤3🥰1
❓ Вопрос: Что показывает команда EXPLAIN ANALYZE в Postgres, в отличие от EXPLAIN?
Anonymous Quiz
8%
План выполнения запроса
84%
План выполнения и статистику по времени выполнения
8%
Статистику по использованию индексов
0%
Список таблиц, участвующих в запросе
👍40🤩27🎉12❤11🔥10
Нияз Хадимуллин | Ментор по GO
❓ Вопрос: Что показывает команда EXPLAIN ANALYZE в Postgres, в отличие от EXPLAIN?
Итак, уважаемые знатоки, внимание, вопрос... Что показывает команда EXPLAIN ANALYZE в Postgres, в отличие от EXPLAIN?
📊 86% проголосовавших в опросе выбрали верный вариант!
⁉️ Правильный ответ: План выполнения и статистику по времени выполнения.
💡 Почему так?
1. EXPLAIN: Показывает, как Postgres планирует выполнить запрос, включая операции (например, сканирование таблиц, использование индексов) и оценку стоимости. Запрос при этом не выполняется. Например:
Запрос
Вывод
2. EXPLAIN ANALYZE: Выполняет запрос и добавляет фактические данные: время выполнения, количество обработанных строк и другие метрики. Например:
Запрос
Вывод
Важно понимать, хоть EXPLAIN и не выполняет запрос, а только показывает план, EXPLAIN ANALYZE может быть затратным для тяжелых запросов, так как он выполняет их полностью.
‼️ Таким образом, EXPLAIN используется, когда нужно быстро понять, как Postgres планирует выполнить запрос, без затрат на его выполнение. EXPLAIN ANALYZE же используется, когда нужно точно определить узкие места в производительности запроса, особенно для тяжелых запросов.
📊 86% проголосовавших в опросе выбрали верный вариант!
💡 Почему так?
1. EXPLAIN: Показывает, как Postgres планирует выполнить запрос, включая операции (например, сканирование таблиц, использование индексов) и оценку стоимости. Запрос при этом не выполняется. Например:
Запрос
EXPLAIN SELECT * FROM users WHERE age > 34;
Вывод
Seq Scan on users (cost=0.00..16.00 rows=420 width=34)
Filter: (age > 34)
2. EXPLAIN ANALYZE: Выполняет запрос и добавляет фактические данные: время выполнения, количество обработанных строк и другие метрики. Например:
Запрос
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 24;
Вывод
Seq Scan on users (cost=0.00..15.00 rows=500 width=36) (actual time=0.034..0.300 rows=450 loops=1)
Filter: (age > 24)
Rows Removed by Filter: 50
Planning Time: 0.052 ms
Execution Time: 0.322 ms
Важно понимать, хоть EXPLAIN и не выполняет запрос, а только показывает план, EXPLAIN ANALYZE может быть затратным для тяжелых запросов, так как он выполняет их полностью.
‼️ Таким образом, EXPLAIN используется, когда нужно быстро понять, как Postgres планирует выполнить запрос, без затрат на его выполнение. EXPLAIN ANALYZE же используется, когда нужно точно определить узкие места в производительности запроса, особенно для тяжелых запросов.
👍30🤩25🎉15❤13🥰5🔥4👏4
День 2️⃣
На ночь глядя поговорим о WaitGroup в Go и уровнях изоляции транзакций в базах данных.
Сегодня у нас параллельное программирование и надёжность данных, поехали 🚀
На ночь глядя поговорим о WaitGroup в Go и уровнях изоляции транзакций в базах данных.
Сегодня у нас параллельное программирование и надёжность данных, поехали 🚀
🔥32👍25❤20🥰20👏13
Что произойдет, если вызвать Done() у WaitGroup больше раз, чем Add()?
Anonymous Quiz
27%
Программа продолжит работу без ошибок
50%
Возникнет паника с ошибкой
9%
WaitGroup автоматически сбросится до нуля
14%
Программа зависнет в deadlock
👍37🔥21❤18🥰9
Нияз Хадимуллин | Ментор по GO
Что произойдет, если вызвать Done() у WaitGroup больше раз, чем Add()?
Итак, уважаемые разработчики, внимание!
📊 75% проголосовавших выбрали правильный ответ.
⁉️ Правильный ответ: Возникнет паника с ошибкой.
💡 Давайте детально разберем почему:
WaitGroup в Go - это счетчик, который следит за количеством активных горутин. Когда счетчик достигает нуля, WaitGroup разблокирует основную горутину. Рассмотрим как это работает:
1. Add(n) увеличивает счетчик на n
2. Done() эквивалентен Add(-1)
3. Wait() блокируется, пока счетчик не станет равным 0
Что происходит при избыточных Done():
Паника возникает, потому что отрицательный счетчик означает логическую ошибку в программе, что помогает обнаружить проблемы синхронизации на ранней стадии.
Как правильно использовать:
‼️ Итого: паника при отрицательном счетчике - это механизм защиты, который помогает обнаружить ошибки синхронизации. Всегда следите за балансом Add() и Done() вызовов!
📊 75% проголосовавших выбрали правильный ответ.
⁉️ Правильный ответ: Возникнет паника с ошибкой.
💡 Давайте детально разберем почему:
WaitGroup в Go - это счетчик, который следит за количеством активных горутин. Когда счетчик достигает нуля, WaitGroup разблокирует основную горутину. Рассмотрим как это работает:
1. Add(n) увеличивает счетчик на n
2. Done() эквивалентен Add(-1)
3. Wait() блокируется, пока счетчик не станет равным 0
Что происходит при избыточных Done():
package main
import (
"sync"
"fmt"
)
func main() {
var wg sync.WaitGroup
wg.Add(1) // счетчик = 1
go func() {
defer wg.Done() // счетчик = 0
}()
wg.Done() // счетчик = -1, ПАНИКА!
wg.Wait()
}
Паника возникает, потому что отрицательный счетчик означает логическую ошибку в программе, что помогает обнаружить проблемы синхронизации на ранней стадии.
Как правильно использовать:
var wg sync.WaitGroup
// ✅ Правильно:
wg.Add(n) // добавляем n горутин
// запускаем n горутин
for i := 0; i < n; i++ {
go func() {
defer wg.Done() // каждая горутина вызывает Done() один раз
}()
}
wg.Wait()
‼️ Итого: паника при отрицательном счетчике - это механизм защиты, который помогает обнаружить ошибки синхронизации. Всегда следите за балансом Add() и Done() вызовов!
🔥32👏24❤17👍15🥰5
Какой уровень изоляции транзакций НЕ защищает от проблемы Lost Update?
Anonymous Quiz
84%
READ COMMITTED
7%
REPEATABLE READ
3%
SERIALIZABLE
6%
Все защищают
❤37🔥33👍19🥰14👏5
Нияз Хадимуллин | Ментор по GO
Какой уровень изоляции транзакций НЕ защищает от проблемы Lost Update?
📊 93% проголосовавших выбрали верный ответ.
⁉️ Правильный ответ: READ COMMITTED не защищает от Lost Update.
💡 Почему?
Lost Update - это ситуация, когда 2 транзакции параллельно читают и обновляют одни и те же данные. Изменения одной транзакции перезаписывают изменения другой, в результате чего теряется обновление первой транзакции.
Потеря данных происходит из-за того, что READ COMMITTED позволяет читать только зафиксированные данные, но не запрещает параллельное изменение прочитанных данных, из-за чего вторая транзакция затирает первую.
❌ READ COMMITTED. Не защищает от параллельных изменений. Транзакции могут видеть изменения, сделанные другими транзакциями, что может привести к потере обновлений.
✅ REPEATABLE READ. Транзакции видят снимок данных на момент начала, используя версионирование (MVCC). Первая транзакция получит ошибку при COMMIT, если другая транзакция пытается изменить ту же строку.
✅ SERIALIZABLE. Полная изоляция транзакций. Выполнение становится последовательным, предотвращая все проблемы с конкурентностью.
‼️ Итог: READ COMMITTED - это компромисс между производительностью и изоляцией. Для защиты от Lost Update используйте более высокие уровни изоляции или явные блокировки!
⁉️ Правильный ответ: READ COMMITTED не защищает от Lost Update.
💡 Почему?
Lost Update - это ситуация, когда 2 транзакции параллельно читают и обновляют одни и те же данные. Изменения одной транзакции перезаписывают изменения другой, в результате чего теряется обновление первой транзакции.
Потеря данных происходит из-за того, что READ COMMITTED позволяет читать только зафиксированные данные, но не запрещает параллельное изменение прочитанных данных, из-за чего вторая транзакция затирает первую.
❌ READ COMMITTED. Не защищает от параллельных изменений. Транзакции могут видеть изменения, сделанные другими транзакциями, что может привести к потере обновлений.
✅ REPEATABLE READ. Транзакции видят снимок данных на момент начала, используя версионирование (MVCC). Первая транзакция получит ошибку при COMMIT, если другая транзакция пытается изменить ту же строку.
✅ SERIALIZABLE. Полная изоляция транзакций. Выполнение становится последовательным, предотвращая все проблемы с конкурентностью.
‼️ Итог: READ COMMITTED - это компромисс между производительностью и изоляцией. Для защиты от Lost Update используйте более высокие уровни изоляции или явные блокировки!
👏65❤63🔥58👍56🥰32
🌠 Предлагаем вам бонусный пост на ночь. Давайте поговорим о том, как multi-stage builds в Docker могут значительно улучшить ваши процессы сборки и развертывания.
📦 Multi-stage builds в Docker - это техника, позволяющая использовать несколько этапов сборки в одном Dockerfile. Каждый этап может использовать разные базовые образы и инструменты, а затем копировать только необходимые артефакты в финальный образ.
💡 Пример:
⁉️ Почему это лучше?
1. Уменьшение размера образа. В финальный образ попадают только необходимые артефакты, что значительно уменьшает его размер.
2. Улучшение безопасности. В конечном образе отсутствуют инструменты и зависимости, используемые только на этапе сборки, что снижает поверхность атаки.
3. Упрощение управления зависимостями. Каждый этап может использовать свои собственные зависимости и инструменты, что упрощает управление ими.
4. Быстрая сборка. Использование кэша Docker для каждого этапа позволяет ускорить процесс сборки, так как повторные сборки используют уже собранные артефакты.
‼️ Multi-stage builds в Docker - это мощный инструмент для оптимизации процесса сборки образов. Он позволяет создавать более легкие, безопасные и быстрые образы, что особенно важно для развертывания в облачных средах и контейнерных оркестраторах, таких как Kubernetes.
❤️ Если вам понравился этот пост, ставьте реакции, и мы будем выкладывать ещё больше подобного контента!
📦 Multi-stage builds в Docker - это техника, позволяющая использовать несколько этапов сборки в одном Dockerfile. Каждый этап может использовать разные базовые образы и инструменты, а затем копировать только необходимые артефакты в финальный образ.
💡 Пример:
# Первый этап. Сборка приложения
FROM golang:1.23 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
# Второй этап. Создание минимального образа
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]
⁉️ Почему это лучше?
1. Уменьшение размера образа. В финальный образ попадают только необходимые артефакты, что значительно уменьшает его размер.
2. Улучшение безопасности. В конечном образе отсутствуют инструменты и зависимости, используемые только на этапе сборки, что снижает поверхность атаки.
3. Упрощение управления зависимостями. Каждый этап может использовать свои собственные зависимости и инструменты, что упрощает управление ими.
4. Быстрая сборка. Использование кэша Docker для каждого этапа позволяет ускорить процесс сборки, так как повторные сборки используют уже собранные артефакты.
‼️ Multi-stage builds в Docker - это мощный инструмент для оптимизации процесса сборки образов. Он позволяет создавать более легкие, безопасные и быстрые образы, что особенно важно для развертывания в облачных средах и контейнерных оркестраторах, таких как Kubernetes.
❤️ Если вам понравился этот пост, ставьте реакции, и мы будем выкладывать ещё больше подобного контента!
👍68🔥57🥰49❤36👏7
День 3️⃣
Сегодня разбираем работу с rune и UTF-8 в Go, а также все виды JOIN в SQL.
Поехали 🚀
Сегодня разбираем работу с rune и UTF-8 в Go, а также все виды JOIN в SQL.
Поехали 🚀
👏27❤26👍25🔥15🥰15
Как в Go обрабатываются многобайтовые символы в строках?
Anonymous Quiz
8%
Go автоматически разбивает строку на отдельные байты
92%
Go использует тип rune для представления Unicode-символов, включая многобайтовые
0%
Go не поддерживает многобайтовые символы
0%
Go требует ручного разбиения строки на байты
❤21🥰21👏16🔥13👍12
Какой JOIN вернет все строки из обеих таблиц, даже если нет совпадений, заполняя отсутствующие значения NULL?
Anonymous Quiz
15%
INNER JOIN
0%
LEFT JOIN
8%
RIGHT JOIN
77%
FULL JOIN
🔥37❤28👍12👏7🥰6
Нияз Хадимуллин | Ментор по GO
Как в Go обрабатываются многобайтовые символы в строках?
📊 Аж 100% проголосовавших в опросе выбрали верный вариант!
⁉️ Правильный ответ: Go использует тип
💡 Почему так?
В Go строки представляют собой последовательность байт, но для работы с Unicode-символами (включая многобайтовые, такие как кириллица или эмодзи) используется тип
Пример:
‼️ Таким образом, Go позволяет легко работать с многобайтовыми символами, используя тип
⁉️ Правильный ответ: Go использует тип
rune для представления Unicode-символов, включая многобайтовые. 💡 Почему так?
В Go строки представляют собой последовательность байт, но для работы с Unicode-символами (включая многобайтовые, такие как кириллица или эмодзи) используется тип
rune. rune — это псевдоним для int32, который позволяет хранить Unicode-код символа. Пример:
go
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
str := "Привет, мир! 🚀"
fmt.Println("Длина строки в байтах:", len(str)) // 27 байт
fmt.Println("Длина строки в символах:", utf8.RuneCountInString(str)) // 13 символов
// Итерация по символам
for _, r := range str {
fmt.Printf("%c ", r)
}
}
‼️ Таким образом, Go позволяет легко работать с многобайтовыми символами, используя тип
rune и функции из пакета unicode/utf8.🥰81👍48❤46👏38🔥31
Нияз Хадимуллин | Ментор по GO
Какой JOIN вернет все строки из обеих таблиц, даже если нет совпадений, заполняя отсутствующие значения NULL?
Итак, уважаемые знатоки, внимание, вопрос... Какой JOIN вернет все строки из обеих таблиц, даже если нет совпадений, заполняя отсутствующие значения NULL?
📊 И вновь 100% проголосовавших сегодня в опросе выбрали верный вариант!
⁉️ Правильный ответ: FULL JOIN.
💡 Почему так?
В SQL существует несколько видов JOIN, каждый из которых решает свои задачи:
Во-первых, INNER JOIN: Возвращает только совпадающие строки из обеих таблиц.
Во-вторых, LEFT JOIN: Возвращает все строки из левой таблицы и совпадающие строки из правой. Если совпадений нет, справа будут NULL.
В-третьих, RIGHT JOIN: Возвращает все строки из правой таблицы и совпадающие строки из левой. Если совпадений нет, слева будут NULL.
В-четвертых, FULL JOIN: Возвращает все строки из обеих таблиц. Если совпадений нет, недостающие значения заменяются на NULL.
В-пятых, CROSS JOIN, который в опросе не заявлялся, но его тоже стоит отметить. Возвращает декартово произведение строк. Это означает, что он соединяет каждую строку одной таблицы с каждой строкой другой, в результате чего получается набор всех возможных комбинаций строк из обеих таблиц.
Пример FULL JOIN:
‼️ Таким образом, FULL JOIN — это единственный тип JOIN, который возвращает все строки из обеих таблиц, даже если нет совпадений.
📊 И вновь 100% проголосовавших сегодня в опросе выбрали верный вариант!
⁉️ Правильный ответ: FULL JOIN.
💡 Почему так?
В SQL существует несколько видов JOIN, каждый из которых решает свои задачи:
Во-первых, INNER JOIN: Возвращает только совпадающие строки из обеих таблиц.
Во-вторых, LEFT JOIN: Возвращает все строки из левой таблицы и совпадающие строки из правой. Если совпадений нет, справа будут NULL.
В-третьих, RIGHT JOIN: Возвращает все строки из правой таблицы и совпадающие строки из левой. Если совпадений нет, слева будут NULL.
В-четвертых, FULL JOIN: Возвращает все строки из обеих таблиц. Если совпадений нет, недостающие значения заменяются на NULL.
В-пятых, CROSS JOIN, который в опросе не заявлялся, но его тоже стоит отметить. Возвращает декартово произведение строк. Это означает, что он соединяет каждую строку одной таблицы с каждой строкой другой, в результате чего получается набор всех возможных комбинаций строк из обеих таблиц.
Пример FULL JOIN:
sql
-- FULL JOIN
SELECT users.name, orders.amount
FROM users
FULL JOIN orders ON users.id = orders.user_id;
‼️ Таким образом, FULL JOIN — это единственный тип JOIN, который возвращает все строки из обеих таблиц, даже если нет совпадений.
🥰39👍38🔥38👏26❤16