💬Как в Go реализована композиция (агрегация)? Чем она отличается от наследования?
📌В Go композиция достигается путем встраивания одной структуры в другую. Например, встраивание одной структуры в другую позволяет получить доступ к полям встроенной структуры, как если бы они были полями внешней структуры. Композиция в Go более гибкая и рекомендуется как альтернатива наследованию.
📌В нашем примере:
• Определен базовый тип Engine с двумя полями (Power и Type) и методом Start.
• Определен тип Car, в который встраивается Engine.
• В функции main создается экземпляр типа Car, и через этот экземпляр вызывается метод Start встроенного типа Engine, а также обращаются к полям встроенного типа Engine.
📌Таким образом, композиция в Go позволяет объединять простые типы в более сложные структуры, сохраняя при этом простоту и ясность кода.
📌В Go композиция достигается путем встраивания одной структуры в другую. Например, встраивание одной структуры в другую позволяет получить доступ к полям встроенной структуры, как если бы они были полями внешней структуры. Композиция в Go более гибкая и рекомендуется как альтернатива наследованию.
📌В нашем примере:
• Определен базовый тип Engine с двумя полями (Power и Type) и методом Start.
• Определен тип Car, в который встраивается Engine.
• В функции main создается экземпляр типа Car, и через этот экземпляр вызывается метод Start встроенного типа Engine, а также обращаются к полям встроенного типа Engine.
📌Таким образом, композиция в Go позволяет объединять простые типы в более сложные структуры, сохраняя при этом простоту и ясность кода.
👍14🔥3🤔3
🧑💻 Статьи для IT: как объяснять и распространять значимые идеи
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬Что будет при чтении/записи из закрытого и неинициализированного канала?
📌Чтение из закрытого канала: когда мы пытаемся читать из закрытого канала, происходит следующее:
1. Если в канале остались значения, которые были в него предварительно записаны, операция чтения будет успешной.
2. Если в канале больше нет значений, операция чтения немедленно завершится, и полученное значение будет нулевым значением для типа данных канала.
3. Если канал уже закрыт и в нем нет значений, попытка прочитать из него снова приведет к получению нулевого значения для типа данных канала.
📌Запись в закрытый канал: попытка записать в закрытый канал вызовет панику. Это означает, что запись в закрытый канал является недопустимой операцией.
📌Чтение из неинициализированного (nil) канала будет заблокировано, как и запись в неициализированный (nil) канал.
☝️Важно отслеживать состояния каналов, инициализировать и закрывать их по мере необходимости, чтобы избежать паник и непредсказуемого поведения.
📌Чтение из закрытого канала: когда мы пытаемся читать из закрытого канала, происходит следующее:
1. Если в канале остались значения, которые были в него предварительно записаны, операция чтения будет успешной.
2. Если в канале больше нет значений, операция чтения немедленно завершится, и полученное значение будет нулевым значением для типа данных канала.
3. Если канал уже закрыт и в нем нет значений, попытка прочитать из него снова приведет к получению нулевого значения для типа данных канала.
ch := make(chan int)
close(ch)
value, ok := <-ch
fmt.Println(value, ok)
// 0 false📌Запись в закрытый канал: попытка записать в закрытый канал вызовет панику. Это означает, что запись в закрытый канал является недопустимой операцией.
ch := make(chan int)
close(ch)
ch <- 42
// panic: send on closed channel📌Чтение из неинициализированного (nil) канала будет заблокировано, как и запись в неициализированный (nil) канал.
☝️Важно отслеживать состояния каналов, инициализировать и закрывать их по мере необходимости, чтобы избежать паник и непредсказуемого поведения.
👍8😁2⚡1
💬Что такое паника (panic) в Go? Какие операции автоматически возвращают панику и останавливают программу?
📌Паники относятся к категории ошибок, которые не ожидались разработчиком. Паника похожа на исключения в других ЯП и предназначена только для ошибок времени выполнения, например:
🔸Доступ к индексу за пределами массива/среза: попытка доступа к элементу массива или среза по индексу за пределами его размера приведет к панике.
🔸Type assertion:
неправильное приведение типа с помощью type assertion может вызвать панику.
🔸Закрытие закрытого канала:
попытка закрыть уже закрытый канал вызовет панику.
📌Обработка паники
Для обработки паники в Go используется конструкция
Если функция
👉 Подробнее
📌Паники относятся к категории ошибок, которые не ожидались разработчиком. Паника похожа на исключения в других ЯП и предназначена только для ошибок времени выполнения, например:
🔸Доступ к индексу за пределами массива/среза: попытка доступа к элементу массива или среза по индексу за пределами его размера приведет к панике.
arr := []int{1, 2, 3}
fmt.Println(arr[5])
// panic: runtime error: index out of range🔸Type assertion:
неправильное приведение типа с помощью type assertion может вызвать панику.
var i interface{} = "hello"
fmt.Println(i.(int))
// panic: interface conversion: interface {} is string, not int🔸Закрытие закрытого канала:
попытка закрыть уже закрытый канал вызовет панику.
ch := make(chan int)
close(ch)
close(ch)
// panic: close of closed channel📌Обработка паники
Для обработки паники в Go используется конструкция
recover
. Recover
возвращает значение, переданное функции panic
, если вызов recover
происходит в той же горутине, что и panic
. Это часто используется в сочетании с defer
, чтобы обеспечить обработку паники и предотвратить завершение всей программы.func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
causePanic()
fmt.Println("This line will not be reached")
}
func causePanic() {
panic("This is a panic")
}
Если функция
causePanic
вызывает панику, функция defer
будет вызвана перед завершением программы. Функция recover
затем используется для захвата значения паники и предотвращения завершения программы.👉 Подробнее
Digitalocean
Обработка паник в Go | DigitalOcean
Ошибки, возникающие в программе, относятся к двум широким категориям: ожидаемые программистом ошибки и ошибки, возникновения которых не ожидалось. Интерфейс …
👍10❤2
💬В чем разница между context.Background() и context.TODO()?
📌Разница между
👉
📌Разница между
context.Background()
и context.TODO()
в основном заключается в их семантическом использовании.👉
context.Background()
используется как стартовый контекст, а context.TODO()
указывает на то, что контекст будет предоставлен позже, другими словами, когда неясно, какой контекст использовать, или он еще недоступен. С точки зрения функциональности они идентичны.🔥13👍2
💬Что из себя представляет стабы (stubs) и моки (mock) в контексте тестирования в Go?
📌Стабы (stubs) и моки (mocks) являются техниками, используемыми для изоляции тестируемого кода от внешних зависимостей во время тестирования в Go.
🔸Стабы (stubs) — это фейковые объекты, которые предоставляют предопределенные ответы на вызовы методов во время тестирования.
🔸Моки (mocks) — это более продвинутые фейковые объекты, которые, кроме предоставления предопределенных ответов, также проверяют, как и когда методы были вызваны в тестах, что помогает в проверке взаимодействия между объектами.
📌В первом примере создается стаб
📌Стабы (stubs) и моки (mocks) являются техниками, используемыми для изоляции тестируемого кода от внешних зависимостей во время тестирования в Go.
🔸Стабы (stubs) — это фейковые объекты, которые предоставляют предопределенные ответы на вызовы методов во время тестирования.
package main
import "fmt"
type DatabaseStub struct{}
func (db *DatabaseStub) GetUserName(id int) string {
return "Alice"
}
type Database interface {
GetUserName(id int) string
}
func PrintUserName(db Database, id int) {
name := db.GetUserName(id)
fmt.Println(name)
}
func main() {
dbStub := &DatabaseStub{}
PrintUserName(dbStub, 1)
}
🔸Моки (mocks) — это более продвинутые фейковые объекты, которые, кроме предоставления предопределенных ответов, также проверяют, как и когда методы были вызваны в тестах, что помогает в проверке взаимодействия между объектами.
package main
import (
"github.com/stretchr/testify/mock"
"testing"
)
type DatabaseMock struct {
mock.Mock
}
func (db *DatabaseMock) GetUserName(id int) string {
args := db.Called(id)
return args.String(0)
}
func TestPrintUserName(t *testing.T) {
dbMock := new(DatabaseMock)
dbMock.On("GetUserName", 1).Return("Alice")
name := dbMock.GetUserName(1)
dbMock.AssertExpectations(t)
}
📌В первом примере создается стаб
DatabaseStub
, который имеет метод GetUserName
. Во втором примере создается мок DatabaseMock
с использованием библиотеки testify
, который проверяет, был ли метод GetUserName
вызван с правильным аргументом.👍5⚡1
💬Что из себя представляют структурные теги в Go?
🔸Теги структур в Go — это метаданные, прикрепленные к полям структуры, которые могут быть использованы для предоставления дополнительной информации или инструкций внешним пакетам или библиотекам.
🔸Они представляют собой строковые литералы, расположенные в бэктиках (`` ` ``) в объявлении поля структуры.
📌Пример тега структуры в Go:
🔸В этом примере `
📌Теги структур могут быть использованы для различных целей, включая:
1. Контроль сериализации и десериализации: теги могут указывать, как поля должны быть сериализованы или десериализованы в форматы, такие как JSON или XML. Например, тег `
2. Валидация данных: теги могут быть использованы для указания правил валидации для полей, например, минимальной или максимальной длины строки.
3. Описания и документация: теги могут содержать документацию или описания полей.
4. Оркестровка баз данных: теги могут быть использованы для маппинга полей структуры на столбцы в базе данных.
5. Другие кастомные обработки: теги могут быть использованы для произвольной обработки кастомными библиотеками или кодом.
Для доступа к тегам структуры и их разбора часто используется пакет `
👉 Подробнее
🔸Теги структур в Go — это метаданные, прикрепленные к полям структуры, которые могут быть использованы для предоставления дополнительной информации или инструкций внешним пакетам или библиотекам.
🔸Они представляют собой строковые литералы, расположенные в бэктиках (`` ` ``) в объявлении поля структуры.
📌Пример тега структуры в Go:
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
🔸В этом примере `
json:"name"
` и `json:"age"
` являются тегами структуры для полей `Name
` и `Age
` соответственно. Эти теги могут быть использованы пакетом `encoding/json
` для управления тем, как объекты `Person
` сериализуются/десериализуются в/из JSON.📌Теги структур могут быть использованы для различных целей, включая:
1. Контроль сериализации и десериализации: теги могут указывать, как поля должны быть сериализованы или десериализованы в форматы, такие как JSON или XML. Например, тег `
json:"name,omitempty"
` указывает, что поле `Name
` должно быть сериализовано как `name
` в JSON, и если поле пустое, его следует опустить.2. Валидация данных: теги могут быть использованы для указания правил валидации для полей, например, минимальной или максимальной длины строки.
3. Описания и документация: теги могут содержать документацию или описания полей.
4. Оркестровка баз данных: теги могут быть использованы для маппинга полей структуры на столбцы в базе данных.
5. Другие кастомные обработки: теги могут быть использованы для произвольной обработки кастомными библиотеками или кодом.
Для доступа к тегам структуры и их разбора часто используется пакет `
reflect
`. Этот пакет предоставляет функции для работы с типами и значениями во время выполнения, что позволяет изучать и изменять значения, типы и теги структур во время выполнения.Please open Telegram to view this post
VIEW IN TELEGRAM
Digitalocean
Использование тегов структур в Go | DigitalOcean
Структуры используются для сбора различных элементов информации внутри одной единицы. Эти наборы информации используются для описания концепций более высоког…
👍12❤2
💬Что такое `json:,omitempty` в контексте структур Go?
🔹Если вы читали предыдущий пост, наверняка заметили упоминание аннотации `
🔹`
🔹В приведенном выше примере без тега
👉 Подробнее
🔹Если вы читали предыдущий пост, наверняка заметили упоминание аннотации `
json:,omitempty
`. Например:type fruit struct {
Name string
Length int `json:,omitempty`
}
🔹`
json:,omitempty
` — это тег JSON для поля в структуре. Если при демаршаллинге данных JSON в структуру это конкретное поле пусто, оно будет игнорироваться. Без тега omitempty
будет использоваться значение по умолчанию.🔹В приведенном выше примере без тега
omitempty
поле длины будет заполнено значением int 0
. Если тип пустого поля — строка, "" (пустая строка) будет значением по умолчанию. Аналогично, значение по умолчанию для логического типа — false
, nil
для указателя, интерфейса, среза и мапы.Please open Telegram to view this post
VIEW IN TELEGRAM
Codingcucumbers
What Is json:,omitempty In Go?
Find out more about the omitempty tag in Go - how to use them, when to use them and more about tags in general
👍8🤔1
💬Какова цель функции init() в Go?
📌Функция
📌Несколько ключевых моментов:
1. Автоматический вызов: функция
2. Использование: функции
3. Несколько функций
4. В случае зависимостей между пакетами, функции
👉 Подробнее
📌Функция
init()
в Go вызывается автоматически при инициализации пакета. В Go нет конструкторов в классическом понимании, как в некоторых других ЯП, но функция init()
предлагает возможность выполнять необходимую начальную настройку. 📌Несколько ключевых моментов:
1. Автоматический вызов: функция
init()
вызывается автоматически перед вызовом main()
и не требует явного вызова.2. Использование: функции
init()
можно использовать для инициализации глобальных переменных, проверки или установки конфигурации, установки соединений с базами данных и других целей.3. Несколько функций
init()
: в одном пакете можно иметь несколько функций init()
. Они будут вызваны в том порядке, в котором объявлены в файле.4. В случае зависимостей между пакетами, функции
init()
из импортированных пакетов выполняются перед функцией init()
из основного пакета.Please open Telegram to view this post
VIEW IN TELEGRAM
Digitalocean
Функция init в Go | DigitalOcean
В Go заданнная функция init() выделяет элемент кода, который запускатся до любой другой части вашего пакета. Этот код запускается сразу же после импорта паке…
👍5
💬Как переобъявить переменные с помощью коротких объявлений?
📌В одной области видимости нельзя переобъявлять переменные, но это можно делать в объявлении нескольких переменных (multi-variable declarations), среди которых хотя бы одна — новая. Переобъявляемые переменные должны располагаться в том же блоке, иначе получится затенённая переменная.
📌Неправильно:
📌Правильно:
📌В одной области видимости нельзя переобъявлять переменные, но это можно делать в объявлении нескольких переменных (multi-variable declarations), среди которых хотя бы одна — новая. Переобъявляемые переменные должны располагаться в том же блоке, иначе получится затенённая переменная.
📌Неправильно:
func main() {
one := 0
one := 1
// ошибка компиляции
}
📌Правильно:
func main() {
one := 0
one, two := 1,2
one,two = two,one
}
👍10
💬В чем разница между пакетами и модулями Go?
📌В Go, пакет — это коллекция исходных файлов
📌Файлы для одного пакета должны находиться в одной директории. Полное имя для пакета строится из имени модуля и пути к директории с файлами.
◆ Например, в
◆ Например, в дереве исходников нашей библиотеки есть файлы в директоории
📌В Go, пакет — это коллекция исходных файлов
.go
в одной директории и с одинаковой директивой package
, в то время как модуль — это дерево пакетов. Имя модуля задаётся в go.mod
.📌Файлы для одного пакета должны находиться в одной директории. Полное имя для пакета строится из имени модуля и пути к директории с файлами.
◆ Например, в
go.mod
указано module example.org/mylib
, тогда все пакеты из модуля example.org/mylib
должны быть в дочерних директориях относительно go.mod
, и путь к директории определяет имя пакета.◆ Например, в дереве исходников нашей библиотеки есть файлы в директоории
./cmd/root
. Тогда эти файлы должны быть либо с директивой package root
, либо package root_test
. И полное имя пакета для этих файлов будет либо example.org/mylib/cmd/root
, либо example.org/mylib/cmd/root_test
(
тесты для пакета example.org/mylib/cmd/root)
.👍12
💬Предположим, что мы хотим выполнить код Go в какой-то момент в будущем или повторно через определенный интервал. Что необходимо использовать в таком случае?
📌Встроенные функции
🔹Таймеры (первый пример):
◆ Таймеры представляют собой способ ожидания определенного времени перед выполнением действия.
◆ Создание таймера выполняется с помощью функции
◆ В примере таймер имеет канал
◆ Также возможно остановить таймер перед его активацией с помощью метода
🔹Тикеры (второй пример):
◆ Тикеры используются для выполнения действий через регулярные промежутки времени.
◆ Создание тикера также выполняется с помощью функции в пакете
◆ Аналогично таймерам, тикеры имеют канал
◆ Тикеры можно остановить, используя метод
📌Встроенные функции
timer
и ticker
упрощают обе задачи, при этом таймеры предназначены для кейсов, когда мы хотим сделать что-то один раз в будущем, а тикеры — для кейсов, когда мы хотим сделать что-то повторно через определенные промежутки времени.🔹Таймеры (первый пример):
◆ Таймеры представляют собой способ ожидания определенного времени перед выполнением действия.
◆ Создание таймера выполняется с помощью функции
time.NewTimer()
; в нее передаем длительность времени, которую необходимо ожидать.◆ В примере таймер имеет канал
C
, в который будет отправлено значение после истечения заданного времени.◆ Также возможно остановить таймер перед его активацией с помощью метода
Stop()
.🔹Тикеры (второй пример):
◆ Тикеры используются для выполнения действий через регулярные промежутки времени.
◆ Создание тикера также выполняется с помощью функции в пакете
time
, в данном случае time.NewTicker()
, с указанием интервала между «тиками».◆ Аналогично таймерам, тикеры имеют канал
C
, в который отправляется значение на каждом «тике».◆ Тикеры можно остановить, используя метод
Stop()
, что предотвратит дальнейшее отправление значений.👍9🥱4
💬Как обрабатывать сигналы Unix в Go?
🔸Обработка сигналов UNIX в Go обычно выполняется с использованием пакета
📌Простой пример:
1. Импортируем пакет
2. Создаем канал, который будет использоваться для получения сигналов:
3. Используем функцию
4. Используем
// обработка сигнала
📌Программа ожидает сигналы
👉 Подробнее
🔸Обработка сигналов UNIX в Go обычно выполняется с использованием пакета
os/signal
. 📌Простой пример:
1. Импортируем пакет
os/signal
и syscall
:import (
"os"
"os/signal"
"syscall"
)
2. Создаем канал, который будет использоваться для получения сигналов:
signals := make(chan os.Signal, 1)
3. Используем функцию
signal.Notify
, чтобы указать, какие сигналы мы хотим обрабатывать:signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
4. Используем
select
в горутине или в основном потоке программы для ожидания сигналов и реагирования на них:select {
case sig := <-signals:
// обработка сигнала
fmt.Printf("received signal %v\n", sig)
}
📌Программа ожидает сигналы
SIGINT
и SIGTERM
, и когда она их получит, выведет полученный сигнал. Это базовый пример того, как можно обрабатывать сигналы в Go. 👉 Подробнее
👍13
💬 Что возвращает функция len() в Go, если ей передана строка в кодировке UTF-8?
🔸Функция
🔸Если строка закодирована в UTF-8, каждый символ может занимать от 1 до 4 байтов.
🔸Таким образом, если в строке UTF-8 присутствуют многобайтовые символы, функция
🔸Результат:
Byte length: 6
Rune count: 2
🔸Функция
len()
в Go возвращает количество байтов в строке, а не количество рун (символов Unicode).🔸Если строка закодирована в UTF-8, каждый символ может занимать от 1 до 4 байтов.
🔸Таким образом, если в строке UTF-8 присутствуют многобайтовые символы, функция
len()
вернет значение, большее, чем количество символов в строке.
import (
"fmt"
"unicode/utf8"
)
func main() {
s := "世界"
fmt.Println("Byte length:", len(s))
fmt.Println("Rune count:", utf8.RuneCountInString(s))
}
🔸Результат:
Byte length: 6
Rune count: 2
👍6
💬Какие риски возникают при использовании нескольких тегов полей в одной структуре?
📌Основная проблема при использовании нескольких тегов полей в одной структуре заключается в том, что это может привести к тесной связанности между различными слоями нашего приложения.
📌Простой пример:
🔸В примере у структуры Po
🔸При использовании подобных тегов слой HTTP-ответа (веб-сервер) и слой хранения (MongoDB) становятся тесно связанными. Если мы хотим изменить ti
📌Основная проблема при использовании нескольких тегов полей в одной структуре заключается в том, что это может привести к тесной связанности между различными слоями нашего приложения.
📌Простой пример:
type Post struct {
Title string `json:"title" bson:"title"`
SubTitle string `json:"subtitle" bson:"subtitle"`
}
🔸В примере у структуры Po
st д
ля каждого поля есть два тега поля: json и
bson.
Эти теги могут использоваться в разных целях, например, для отправки HTTP-ответов (используя json)
и обработки демаршализации MongoDB (используя bson).
🔸При использовании подобных тегов слой HTTP-ответа (веб-сервер) и слой хранения (MongoDB) становятся тесно связанными. Если мы хотим изменить ti
tle н
а, например, shortTitle,
нам нужно будет обновить и HTTP-ответ (что также может повлиять на клиентов, обрабатывающих ответ), и хранение в MongoDB.👍1
🧑💻 Статьи для IT: как объяснять и распространять значимые идеи
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬Где полезен встроенный метод recover в Go?
Встроенный метод
// Плохо
func main() {
defer recover()
panicCode()
}
// Лучше
📌Кроме того:
🔸Обработка ошибок: в ситуациях, когда паника является возможной и ожидаемой, например, при работе с внешними ресурсами или библиотеками, которые могут вызывать панику, re
🔸Неотложное восстановление: в демонизированных приложениях или долго работающих процессах, где стабильность имеет критическое значение, re
🔸Откат транзакций: в операциях, которые должны быть атомарными, таких как обновления базы данных, re
🔸Логирование и отладка: re
Встроенный метод
recover
действительно полезен в отложенных функциях, но не рекомендуется вызывать его напрямую с помощью ключевого слова defer
.// Плохо
func main() {
defer recover()
panicCode()
}
// Лучше
func handlePanic() {
if panicInfo := recover(); panicInfo != nil {
fmt.Println(panicInfo)
}
}
func main() {
defer handlePanic()
panicCode()
}
📌Кроме того:
🔸Обработка ошибок: в ситуациях, когда паника является возможной и ожидаемой, например, при работе с внешними ресурсами или библиотеками, которые могут вызывать панику, re
cover м
ожет быть использован для возврата ошибки вместо завершения программы.🔸Неотложное восстановление: в демонизированных приложениях или долго работающих процессах, где стабильность имеет критическое значение, re
cover м
ожет использоваться для обеспечения того, чтобы временная ошибка не привела к полному сбою системы.🔸Откат транзакций: в операциях, которые должны быть атомарными, таких как обновления базы данных, re
cover м
ожет использоваться для обнаружения паники и выполнения отката транзакции, чтобы поддерживать целостность данных.🔸Логирование и отладка: re
cover м
ожет использоваться для перехвата паники, логирования диагностической информации и затем повторного вызова паники, чтобы стандартный процесс обработки ошибок мог продолжить работу.❤8👍1
💬Для чего в Go предназначена директива "//go:embed"
📌Начиная с Go 1.16, директива
📌Во время выполнения, эти ресурсы становятся доступны через переменную, к которой применяется директива. Нам не нужно заботиться о механизмах пути к файлу или открытии и чтении файлов во время выполнения, что упрощает распространение программ, требующих доступа к внешним файлам.
Простой пример:
Все файлы в директории static встраиваются в бинарный файл. Директива //
Этот функционал особенно полезен, когда мы хотим создать самодостаточное приложение, которое не зависит от внешних файлов во время выполнения.
👉 Подробнее
?
📌Начиная с Go 1.16, директива
//go:embed
представляет собой специальный комментарий, который используется для встраивания файлов и директорий непосредственно в скомпилированный бинарный файл Go.📌Во время выполнения, эти ресурсы становятся доступны через переменную, к которой применяется директива. Нам не нужно заботиться о механизмах пути к файлу или открытии и чтении файлов во время выполнения, что упрощает распространение программ, требующих доступа к внешним файлам.
Простой пример:
package main
import (
"embed"
"io/fs"
"net/http"
)
//go:embed static/*
var staticFiles embed.FS
func main() {
// Используем встроенные файлы напрямую
http.Handle("/", http.FileServer(http.FS(staticFiles)))
http.ListenAndServe(":8080", nil)
}
Все файлы в директории static встраиваются в бинарный файл. Директива //
go:embed д
олжна быть расположена непосредственно перед объявлением переменной без пустых строк между комментарием и объявлением. Это позволяет использовать staticFiles к
ак файловую систему внутри Go-кода.Этот функционал особенно полезен, когда мы хотим создать самодостаточное приложение, которое не зависит от внешних файлов во время выполнения.
👉 Подробнее
👍13🔥2
💬Что в себя включает реализация кастомного обработчика логов с log/slog?
🔸Пакет стандартной библиотеки
🔸Пакет
📌Для создания кастомного обработчика существует 4 метода:
1️⃣ Enabled: представляет собой оптимизацию, позволяющую избежать ненужной работы. Метод вывода
2️⃣ Handle: этому методу передается файл
3️⃣ WithAttrs. Одной из оптимизаций производительности
Обработчик может сохранить атрибуты для последующего использования методом
4️⃣ WithGroup:
👉 Подробнее
🔸Пакет стандартной библиотеки
log/slog
состоит из двух частей: внешней и внутренней. Внешняя часть реализована типом Logger
, собирает структурированную информацию логов, и передает их внутренней части, реализации интерфейса Handler
. 🔸Пакет
slog
поставляется с двумя встроенными обработчиками, которых обычно должно быть достаточно. Но нам может потребоваться написать кастомный обработчик. 📌Для создания кастомного обработчика существует 4 метода:
1️⃣ Enabled: представляет собой оптимизацию, позволяющую избежать ненужной работы. Метод вывода
Logger
будет вызываться Enabled
перед обработкой любого из своих аргументов, чтобы проверить, следует ли продолжать работу.Enabled(context.Context, Level) bool
2️⃣ Handle: этому методу передается файл
Record
, содержащий всю информацию, которая должна быть зарегистрирована для одного вызова метода вывода Logger.Handle(context.Context, Record) error
3️⃣ WithAttrs. Одной из оптимизаций производительности
slog
является поддержка атрибутов предварительного форматирования. Метод Logger.With преобразует пары ключ-значение в Attrs
, а затем вызывает Handler.WithAttrs
. Обработчик может сохранить атрибуты для последующего использования методом
Handle
или может воспользоваться возможностью отформатировать атрибуты сейчас, один раз, а не делать это повторно при каждом вызове Handle
.WithAttrs(attrs []Attr) Handler
4️⃣ WithGroup:
Logger.WithGroup
вызывает Handler.WithGroup
напрямую, с тем же аргументом, именем группы. Обработчик должен запомнить имя, чтобы использовать его для определения всех последующих атрибутов.WithGroup(name string) Handler
👉 Подробнее
❤2👍1