💬 Для чего предназначена директория internal в проекте на Go?
Директория
➕ Преимущества:
▪️Инкапсуляция: мы сигнализируем, что код внутри
▪️Безопасность: Go автоматически запрещает импортировать код из директории
▪️Гибкость в рефакторинге: мы можем свободно изменять код и API внутри
➖ Недостатки (особенности):
▪️Мы не можем импортировать код из
👉 Подробнее
Директория
internal
в Go — это специальная структура проекта, которая делает код, находящийся внутри неё, доступным только для внутреннего использования в текущем модуле или его подмодулях. Она служит для того, чтобы скрыть детали реализации и предотвратить случайное или преднамеренное использование этого кода другими модулями или внешними проектами.➕ Преимущества:
▪️Инкапсуляция: мы сигнализируем, что код внутри
internal
является «частным» и не предназначен для использования другими модулями.▪️Безопасность: Go автоматически запрещает импортировать код из директории
internal
, даже если кто-то захочет это сделать.▪️Гибкость в рефакторинге: мы можем свободно изменять код и API внутри
internal
, не беспокоясь о том, что сломаем зависимости внешних пользователей.➖ Недостатки (особенности):
▪️Мы не можем импортировать код из
internal
, даже если позже это потребуется. Это может вызвать путаницу для новичков, которые не знают этой особенности.👉 Подробнее
go.dev
Organizing a Go module - The Go Programming Language
👍7🌚2❤1🥰1
💬 Для чего предназначен пакет flag в Go?
Пакет flag предоставляет возможность считывать аргументы командной строки (или флаги). Он поддерживает считывание различных типов данных, включая строки, целые числа и логические значения, что делает его универсальным для различных видов приложений.
Простой пример:
👉 Подробнее
Пакет flag предоставляет возможность считывать аргументы командной строки (или флаги). Он поддерживает считывание различных типов данных, включая строки, целые числа и логические значения, что делает его универсальным для различных видов приложений.
Простой пример:
package main
import (
"flag"
"fmt"
)
func main() {
name := flag.String("name", "Worl "a name to say hello to")
flag.Parse()
fmt.Printf("Hello, %s!\n", *name)
}
go run main.go -name=Gopher
Hello, Gopher!
👉 Подробнее
Bytesizego
A Comprehensive Guide to the Flag Package
Reading command line arguments is a common use case for both CLI and API applications - Go makes this very easy to do using just the standard library via the flag package. Let's see how.
👍8❤1
Forwarded from Библиотека Go-разработчика | Golang
📹 Секреты внутреннего устройства аллокатора Go: видеогайд от Владимира Балуна
⏱️ Таймкоды:
00:00 Введение
01:49 Концепция аллокатора
06:09 Линейный аллокатор
11:22 Блочный аллокатор
16:21 Стековый аллокатор
20:18 Устройство malloc
25:01 Недостатки malloc
26:55 Устройство tcmalloc
28:28 Устройство аллокатора Go
32:55 Предсказуемая фрагментация памяти
40:33 Где аллоцируются объекты в Go
51:11 Почему аллокация на стеке работает быстрее, чем в куче
52:35 Расширение и уменьшение стека в Go
58:12 Зачем это все нужно знать (практические примеры)
01:03:37 Пулы объектов (sync.Pool)
01:06:57 Арены (memory arenas)
01:14:30 Аллокатор ОС
▶️ YouTube | Rutube | VK
⏱️ Таймкоды:
00:00 Введение
01:49 Концепция аллокатора
06:09 Линейный аллокатор
11:22 Блочный аллокатор
16:21 Стековый аллокатор
20:18 Устройство malloc
25:01 Недостатки malloc
26:55 Устройство tcmalloc
28:28 Устройство аллокатора Go
32:55 Предсказуемая фрагментация памяти
40:33 Где аллоцируются объекты в Go
51:11 Почему аллокация на стеке работает быстрее, чем в куче
52:35 Расширение и уменьшение стека в Go
58:12 Зачем это все нужно знать (практические примеры)
01:03:37 Пулы объектов (sync.Pool)
01:06:57 Арены (memory arenas)
01:14:30 Аллокатор ОС
▶️ YouTube | Rutube | VK
👍3🔥1
💬 В Go существует возможность скрывать методы с помощью встраивания структур. Как можно сделать так, чтобы метод, реализующий интерфейс, был скрыт при приведении типа, даже если он присутствует у встраиваемой структуры?
Например, есть тип
Теперь, допустим, мы хотим использовать тип
Когда мы вызываем
Хотя
Например, есть тип
A
, который имеет метод Hello()
. Когда мы передаём экземпляр A
в функцию Greet()
, приведение успешно выполнится к интерфейсу Greeter
, и будет вызван метод Hello()
.Теперь, допустим, мы хотим использовать тип
A
, но не хотим, чтобы его метод Hello()
был доступен. Мы можем скрыть его с помощью embedding.Когда мы вызываем
Greet(ANoHello{A: A{}})
, приведение типа к интерфейсу не удаётся.Хотя
ANoHello
встраивает тип A
, который имеет корректный метод Hello()
, приоритет получает неэкспортируемый тип noHello
, который скрывает метод Hello()
.🤔8👍3❤1😁1
🧑💻 Статьи для IT: как объяснять и распространять значимые идеи
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
❤1👍1
Когда в Go следует использовать псевдонимы типов?
Type aliases — полезный инструмент, но их следует использовать с осторожностью. Вот несколько распространённых сценариев, в которых они могут быть особенно полезны:
🔸 Взаимодействие со сторонними библиотеками. Сторонние библиотеки часто используют сложные или неинтуитивно понятные имена типов. В таких случаях можно создать псевдоним типа, чтобы упростить работу с типами.
🔸 Повышение удобочитаемости кода для конкретной предметной области. Если проект включает в себя модели предметной области или бизнес-логику, псевдонимы типов могут повысить читаемость.
🔸 Упрощение дженериков (Go 1.18+)
В Go 1.18 появились дженерики, которые позволяют функциям работать с любым типом данных. Псевдонимы типов могут упростить использование дженериков в сигнатурах функций.
Type aliases — полезный инструмент, но их следует использовать с осторожностью. Вот несколько распространённых сценариев, в которых они могут быть особенно полезны:
🔸 Взаимодействие со сторонними библиотеками. Сторонние библиотеки часто используют сложные или неинтуитивно понятные имена типов. В таких случаях можно создать псевдоним типа, чтобы упростить работу с типами.
type JSONResponse = map[string]interface{}
🔸 Повышение удобочитаемости кода для конкретной предметной области. Если проект включает в себя модели предметной области или бизнес-логику, псевдонимы типов могут повысить читаемость.
type OrderID = string
type PaymentStatus = string
const (
Pending PaymentStatus = "pending"
Completed PaymentStatus = "completed"
Failed PaymentStatus = "failed"
)
🔸 Упрощение дженериков (Go 1.18+)
В Go 1.18 появились дженерики, которые позволяют функциям работать с любым типом данных. Псевдонимы типов могут упростить использование дженериков в сигнатурах функций.
type List[T any] = []T
func printList[T any](list List[T]) {
for _, item := range list {
fmt.Println(item)
}
}
👍12❤2
Forwarded from Библиотека нейросетей | ChatGPT, Midjourney, DeepSeek, Sora
⚡️Разыгрываем флагманский смартфон
«Библиотека программиста» разыгрывает один из трех смартфонов на выбор:
🔹Samsung Galaxy S24 Ultra на 1 ТБ
🔹Xiaomi 14 Ultra на 512 ГБ
🔹iPhone 16 Pro Max на 512 ГБ
🔥 А еще 99 участников розыгрыша получат скидку 50% на наш курс Базовые модели ML и приложения!
Промокод будет действителен до 20 ноября.
Условия просты:
→ подписаться на Библиотека нейротекста
→ подписаться на Библиотека нейрозвука
→ подписаться на Библиотека нейрокартинок
→ нажать на кнопку «Участвовать» под этим постом
Итоги появятся 30 октября в 20:00 по московскому времени в нашем канале Библиотека программиста. Затем мы свяжемся с победителем, который сам выберет смартфон. Тем, кто получит промокод, мы вышлем его в течение недели после окончания розыгрыша.
⚠️ Убедитесь, что вам можно написать в личные сообщения или следите за результатами — если мы не сможем с вами связаться, то не сможем и отправить приз. Доставить мы можем только в города России и Беларуси.
«Библиотека программиста» разыгрывает один из трех смартфонов на выбор:
🔹Samsung Galaxy S24 Ultra на 1 ТБ
🔹Xiaomi 14 Ultra на 512 ГБ
🔹iPhone 16 Pro Max на 512 ГБ
🔥 А еще 99 участников розыгрыша получат скидку 50% на наш курс Базовые модели ML и приложения!
Промокод будет действителен до 20 ноября.
Условия просты:
→ подписаться на Библиотека нейротекста
→ подписаться на Библиотека нейрозвука
→ подписаться на Библиотека нейрокартинок
→ нажать на кнопку «Участвовать» под этим постом
Итоги появятся 30 октября в 20:00 по московскому времени в нашем канале Библиотека программиста. Затем мы свяжемся с победителем, который сам выберет смартфон. Тем, кто получит промокод, мы вышлем его в течение недели после окончания розыгрыша.
⚠️ Убедитесь, что вам можно написать в личные сообщения или следите за результатами — если мы не сможем с вами связаться, то не сможем и отправить приз. Доставить мы можем только в города России и Беларуси.
💬 Для чего предназначен интерфейс
Когда мы открываем файл, буфер или сетевой поток, по умолчанию чтение или запись данных происходит последовательно, начиная с начала и продвигаясь вперёд. Но иногда нужно больше контроля, например, перескочить к конкретному месту в файле или вернуться назад и что-то перечитать.
Для этого существует интерфейс
Его функция принимает два аргумента:
• os.SeekStart: перемещает курсор относительно начала файла.
• os.SeekCurrent: перемещает курсор относительно его текущего положения.
• os.SeekEnd: перемещает курсор относительно конца файла, чаще всего с отрицательным смещением.
io.Seeker
?Когда мы открываем файл, буфер или сетевой поток, по умолчанию чтение или запись данных происходит последовательно, начиная с начала и продвигаясь вперёд. Но иногда нужно больше контроля, например, перескочить к конкретному месту в файле или вернуться назад и что-то перечитать.
Для этого существует интерфейс
io.Seeker.
Он позволяет перемещать указатель файла на другую позицию в файле, чтобы можно было начать чтение или запись с нужного места. Его функция принимает два аргумента:
offset,
который указывает, насколько нужно сместить курсор, и whence,
который задаёт точку отсчёта: • os.SeekStart: перемещает курсор относительно начала файла.
• os.SeekCurrent: перемещает курсор относительно его текущего положения.
• os.SeekEnd: перемещает курсор относительно конца файла, чаще всего с отрицательным смещением.
👍13
Forwarded from Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter
🧪 Чем заменить Postman: 5 отличных инструментов для разработки API
Postman долгое время был основным инструментом для разработки и тестирования API, но сейчас для большинства разработчиков его ограничения стали перевешивать преимущества. Рассмотрим альтернативные инструменты, которые могут предложить больше возможностей, чем Postman — даже в бесплатной версии.
👉Читаем здесь
Postman долгое время был основным инструментом для разработки и тестирования API, но сейчас для большинства разработчиков его ограничения стали перевешивать преимущества. Рассмотрим альтернативные инструменты, которые могут предложить больше возможностей, чем Postman — даже в бесплатной версии.
👉Читаем здесь
🥱3👍2
💬 Можно ли в Go преобразовывать срезы в массивы или указатели на массивы?
Такая возможность была добавлена в Go 1.20. Когда нужно преобразовать срез в массив фиксированного размера, нельзя сделать это напрямую, как показано ниже:
Чтобы преобразовать срез в массив, команда Go обновила эту функцию в Go 1.17. А с выпуском Go 1.20 процесс преобразования стал ещё проще и удобнее с помощью новых литералов:
P. S.: можно использовать
Такая возможность была добавлена в Go 1.20. Когда нужно преобразовать срез в массив фиксированного размера, нельзя сделать это напрямую, как показано ниже:
a := []int{0, 1, 2, 3, 4, 5}
var b[3]int = a[0:3]
// cannot use a[0:3] (value of type []int) as [3]int value in variable
// declaration compiler(IncompatibleAssign)
Чтобы преобразовать срез в массив, команда Go обновила эту функцию в Go 1.17. А с выпуском Go 1.20 процесс преобразования стал ещё проще и удобнее с помощью новых литералов:
// Go 1.20
func main() {
a := []int{0, 1, 2, 3, 4, 5}
b := [3]int(a[0:3])
fmt.Println(b) // [0 1 2]
}
// Go 1.17
func main() {
a := []int{0, 1, 2, 3, 4, 5}
b := *(*[3]int)(a[0:3])
fmt.Println(b) // [0 1 2]
}
P. S.: можно использовать
a[:3]
вместо a[0:3]
.❤15👍11⚡2
🤔 Нужна ли математика на собеседованиях?
🗓 Сегодня в 20:00 встречаемся в прямом эфире, чтобы обсудим роль математики на собеседовании, а также поделимся инсайдами как успешно пройти техническое собеседование! https://proglib.io/w/a1fe2494
🌟 Спикер: Станислав Петров – Senior Data Scientist.
😮 На вебинаре вы узнаете:
😱 Ошибаться — не страшно. Как ошибки и неудачные проекты могут стать ценным опытом. Почему «проекты в стол» способствуют профессиональному росту. И как преодолеть путь от junior до senior.
🙌🏻 Собеседования: можно ли к ним не готовиться?! Поделимся эффективными стратегиями подготовки и расскажем, на что работодатели обращают внимание в первую очередь.
✍️ Разберем реальные тестовые задачи, которые дают на собеседованиях на позицию Data Scientist.
🎁 Бонус: расскажем как проводить эффективное тестирование в маркетинге и их масштабируемость.
🎯 Почему важно посетить вебинар?
• Понимание математических концепций и их применение помогает успешно проходить собеседования и решать реальные задачи.
• Расширьте свой профессиональный кругозор и подготовьтесь к новым карьерным вызовам.
👉 Присоединяйтесь к нам и узнайте, как математика может помочь в вашей карьере https://proglib.io/w/a1fe2494
🗓 Сегодня в 20:00 встречаемся в прямом эфире, чтобы обсудим роль математики на собеседовании, а также поделимся инсайдами как успешно пройти техническое собеседование! https://proglib.io/w/a1fe2494
🌟 Спикер: Станислав Петров – Senior Data Scientist.
😮 На вебинаре вы узнаете:
😱 Ошибаться — не страшно. Как ошибки и неудачные проекты могут стать ценным опытом. Почему «проекты в стол» способствуют профессиональному росту. И как преодолеть путь от junior до senior.
🙌🏻 Собеседования: можно ли к ним не готовиться?! Поделимся эффективными стратегиями подготовки и расскажем, на что работодатели обращают внимание в первую очередь.
✍️ Разберем реальные тестовые задачи, которые дают на собеседованиях на позицию Data Scientist.
🎁 Бонус: расскажем как проводить эффективное тестирование в маркетинге и их масштабируемость.
🎯 Почему важно посетить вебинар?
• Понимание математических концепций и их применение помогает успешно проходить собеседования и решать реальные задачи.
• Расширьте свой профессиональный кругозор и подготовьтесь к новым карьерным вызовам.
👉 Присоединяйтесь к нам и узнайте, как математика может помочь в вашей карьере https://proglib.io/w/a1fe2494
🔥1
Forwarded from Библиотека Go-разработчика | Golang
🔥 Phuong Le представил очередную занимательную серию статей про I/O в Go:
▪️ Go I/O Readers, Writers и Data
▪️ Go I/O Closer, Seeker, WriterTo и ReaderFrom
▪️ Go I/O Readers, Writers и Data
▪️ Go I/O Closer, Seeker, WriterTo и ReaderFrom
👍2
💬 В Go есть несколько способов чтения файла построчно. Чем отличается использование bufio.Scanner от bufio.Reader для построчного чтения, и когда лучше использовать ioutil.ReadFile?
🔸
🔸
🔸
⚡️ Update: функция
🔸
bufio.Scanner
— простой и эффективный способ построчного чтения, который автоматически обрабатывает строки и подойдёт для большинства задач.🔸
bufio.Reader
с ReadString
предоставляет больше контроля над чтением, позволяя задать разделитель, что может быть полезно для нестандартных форматов.🔸
ioutil.ReadFile
используется для чтения всего файла в память, но подходит только для небольших файлов, так как при больших объёмах данных это может перегрузить память.⚡️ Update: функция
ioutil.ReadFile
устарела. Вместо нее используйте os.ReadFile
.👍17❤1🤔1
💬 В Go 1.21 появились аналоги sync.Once. Какие именно и для чего они предназначены?
🔸
🔸
🔸
🔸
OnceFunc
: функция, которая оборачивает другую функцию так, что та выполнится только один раз. Например, если обёртку wrapper()
вызвать несколько раз, внутренняя функция запустится только при первом вызове. Удобно для случаев, когда необходимо гарантировать, что операция выполняется строго один раз, но хочется иметь удобный многократный интерфейс вызова.🔸
OnceValue[T]
: используется для функций, возвращающих одно значение. Это полезно для кеширования результата тяжёлой операции, например загрузки конфигурации, чтобы каждый вызов возвращал тот же результат, экономя ресурсы.🔸
OnceValues[T, K]
: это расширение, позволяющее возвращать несколько значений, включая ошибки, что упрощает обработку потенциальных ошибок во время первого вызова функции. Все последующие вызовы вернут закешированный результат (вместе с ошибкой, если она была).👍23
Forwarded from Библиотека Go-разработчика | Golang
Media is too big
VIEW IN TELEGRAM
🔥 Разработка блога на Go: серия видеоуроков от Jon Calhoun, Go-разработчика и автора gophercises.com / algorithmswithgo.com
▶️ Rendering Raw Markdown
▶️ Rendering Markdown as HTML
▶️ Metadata via Frontmatter
▶️ Index Page
▶️ Rendering Raw Markdown
▶️ Rendering Markdown as HTML
▶️ Metadata via Frontmatter
▶️ Index Page
👍5🌚1
🧑💻 Статьи для IT: как объяснять и распространять значимые идеи
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.
Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.
Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.
👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
Forwarded from Библиотека Go-разработчика | Golang
⚒️ sync.Map в Go: правильный инструмент для правильной работы
Оказывается,
Читайте продолжение серии статей Phuong Le про сложные аспекты Go на простых иллюстрациях👇
👉 Читать
👉 Другие статьи в серии:
• Go sync.Mutex: нормальный/starvation режим
• Go sync.WaitGroup и проблема выравнивания
• Go sync.Pool и механика, стоящая за ним
• Go sync.Cond, самый недооцененный механизм синхронизации
• Пакет singleflight
Оказывается,
sync․Map
под капотом поддерживает две мапы, что может быть неидеально, если вы часто добавляете или удаляете ключи.Читайте продолжение серии статей Phuong Le про сложные аспекты Go на простых иллюстрациях👇
👉 Читать
👉 Другие статьи в серии:
• Go sync.Mutex: нормальный/starvation режим
• Go sync.WaitGroup и проблема выравнивания
• Go sync.Pool и механика, стоящая за ним
• Go sync.Cond, самый недооцененный механизм синхронизации
• Пакет singleflight
👍3🤔1
💬 Как канонизировать строки для экономии памяти в Go?
Во время выполнения программы на Go одинаковые строки иногда не делят один и тот же базовый блок памяти, хотя могли бы. Процесс объединения их в один общий блок памяти называется канонизацией строк. В Go есть несколько способов реализовать канонизацию строк.
1️⃣ Канонизация строк при их совпадении
Вот пример реализации для канонизации строк в слайсе:
Этот способ более эффективен для случаев, когда необходимо канонизировать все строки в слайсе.
2️⃣ Использование unique.Handle из Go 1.23
В Go 1.23 добавлена возможность использовать
Этот способ более гибкий. Достаточно применить функцию
Примечание: метод
Во время выполнения программы на Go одинаковые строки иногда не делят один и тот же базовый блок памяти, хотя могли бы. Процесс объединения их в один общий блок памяти называется канонизацией строк. В Go есть несколько способов реализовать канонизацию строк.
1️⃣ Канонизация строк при их совпадении
if str1 == str2 {
str1 = str2 // освобождаем базовый блок памяти str2
}
Вот пример реализации для канонизации строк в слайсе:
func CanonicalizeStrings(ss []string) {
type S struct {
str string
index int
}
var temp = make([]S, len(ss))
for i := range temp {
temp[i] = S {
str: ss[i],
index: i,
}
}
for i := 0; i < len(temp); {
var k = i+1
for j := k; j < len(temp); j++ {
if temp[j].str == temp[i].str {
temp[j].str = temp[i].str
temp[k], temp[j] = temp[j], temp[k]
k++
}
}
i = k
}
for i := range temp {
ss[temp[i].index] = temp[i].str
}
}
Этот способ более эффективен для случаев, когда необходимо канонизировать все строки в слайсе.
2️⃣ Использование unique.Handle из Go 1.23
В Go 1.23 добавлена возможность использовать
unique.Handle
для удобной канонизации строк.import "unique"
func CanonicalizeString(s string) string {
return unique.Make(s).Value()
}
func CanonicalizeStrings(ss []string) {
for i, s := range ss {
ss[i] = CanonicalizeString(s)
}
}
Этот способ более гибкий. Достаточно применить функцию
CanonicalizeString
ко всем строкам во время выполнения, и тогда все одинаковые строки будут делить одни и те же базовые блоки памяти.Примечание: метод
unique.Make
не всегда подходит для всех ситуаций. Функция unique.Make
выделяет блок памяти для каждой уникальной строки. Если некоторые неравные строки, подлежащие канонизации, уже делят один и тот же блок памяти, unique.Make
выделит новый блок памяти для каждой из строк, что может привести к увеличению использования памяти (вместо экономии).👍11
💬 В Go есть функция
Использование финализаторов может быть небезопасным из-за нескольких факторов:
1. Финализаторы могут сработать не сразу после того, как объект станет неиспользуемым, а в зависимости от цикла GC.
2. Tiny objects: объекты размером менее 16 байт и без указателей (так называемые "tiny objects") могут группироваться вместе, и если хотя бы один объект в группе ещё используется, финализаторы для остальных объектов могут не сработать.
3. Ограничение на привязку к началу блока памяти: финализатор можно установить только для указателя, указывающего на начало блока памяти объекта. Если привязать финализатор к внутреннему полю структуры, программа завершится с ошибкой.
В следующем примере
В этом коде финализатор может либо сработать, либо нет, в зависимости от того, как Go управляет группой маленьких объектов. Это делает использование финализаторов в Go непредсказуемым, и в большинстве случаев рекомендуется использовать явное освобождение ресурсов с методами, такими как
runtime.SetFinalizer
, позволяющая привязать финализатор к объекту. Как она работает и в каких случаях использование финализаторов может быть небезопасным? Приведите пример ситуации, в которой финализатор может не сработать.runtime.SetFinalizer
позволяет привязать функцию (финализатор) к объекту, которая будет выполнена, когда сборщик мусора сочтёт объект неиспользуемым. Финализатор запускается сборщиком мусора, но его выполнение зависит от цикла GC, поэтому точное время выполнения не гарантируется.Использование финализаторов может быть небезопасным из-за нескольких факторов:
1. Финализаторы могут сработать не сразу после того, как объект станет неиспользуемым, а в зависимости от цикла GC.
2. Tiny objects: объекты размером менее 16 байт и без указателей (так называемые "tiny objects") могут группироваться вместе, и если хотя бы один объект в группе ещё используется, финализаторы для остальных объектов могут не сработать.
3. Ограничение на привязку к началу блока памяти: финализатор можно установить только для указателя, указывающего на начало блока памяти объекта. Если привязать финализатор к внутреннему полю структуры, программа завершится с ошибкой.
В следующем примере
FourBytes
является "tiny object", и финализатор может не сработать, если другие объекты из этой же группы продолжают использоваться:type FourBytes struct {
A byte; B byte; C byte; D byte
}
func final() {
a := &FourBytes{}
runtime.SetFinalizer(a, func(a *FourBytes) {
fmt.Println("Финализатор FourBytes вызван")
})
}
func main() {
final()
runtime.GC()
time.Sleep(time.Millisecond)
}
В этом коде финализатор может либо сработать, либо нет, в зависимости от того, как Go управляет группой маленьких объектов. Это делает использование финализаторов в Go непредсказуемым, и в большинстве случаев рекомендуется использовать явное освобождение ресурсов с методами, такими как
Close
или Dispose
.👍8🤔1