Библиотека Go-разработчика | Golang
СтатистикаВсе самое полезное для Go-разработчика в одном канале. Учиться у нас: clc.to/qaSdww По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0 #WXSSA
- Последний пост
- 14 авг.
- Последнее чтение
- 13:21
- Постов за неделю
- 7
- Всего постов
- 310
- Тип
- открытый
- Язык
- русский
- Категория
- Технологии
- В каталоге с
- 12 авг.
- 1/24сутки в ленте
- 2 611
- 1/48двое суток
- 2 992
- 1/72трое суток
- 3 227
Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.
Посты
🔥 Go 1.27 наконец разрешит дженерик-методы Дженерики появились ещё в Go 1.18, но метод до сих пор не может объявить собственные type parameters. Поэтому вместо: func (s Set[T]) Map[U comparable](f func(T) U) Set[U] приходится писать отдельную generic-функцию: func MapSet[T, U comparable](s Set[T], f func(T) U) Set[U] В Go 1.27 это ограничение снимают: собственные type parameters можно будет объявлять прямо у метода. Но есть граница: generic methods не работают как методы интерфейсов и не могут их реализовывать. 📌 Go 1.27 пока не вышел в stable — изменение уже есть в draft release notes, релиз ожидается в августе. 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoLive
❓ Что на самом деле лежит внутри слайса Слайс — не массив, а небольшая структура: type slice struct { array unsafe.Pointer len int cap int } array указывает на массив с данными, len хранит текущую длину, cap — доступную вместимость. Отсюда две важные особенности. 1️⃣ Срез не копирует данные s2 := s1[1:3] s1 и s2 смотрят в один массив. Изменение элемента через s2 может быть видно через s1. 2️⃣ А вот append может разорвать эту связь Пока хватает cap → запись идёт в существующий массив. Не хватает cap → выделяется новый backing array, элементы копируются туда. Поэтому два слайса могут сначала делить память, а после append — уже нет. И наоборот, append без реаллокации способен неожиданно изменить данные, доступные через соседний слайс. 💡 Есть способ контролировать такое поведение через s[low:high:max] — разберём отдельно. 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoDeep
🤷♂️ Почему Go удобен для AI-кодинга Команда Go выпустила разбор о том, почему язык хорошо подходит для работы с AI-агентами. Ключевой аргумент — Go легко проверять: ⬆️gofmt стандартизирует код ⬆️компилятор ловит ошибки ⬆️типов и выдуманные API ⬆️тесты и fuzzing встроены в ⬆️toolchain govulncheck проверяет ⬆️уязвимые зависимости ⬆️go fix и gopls помогают с ⬆️рефакторингом Когда агент пишет код быстрее, чем человек успевает его читать, предсказуемость языка становится отдельным преимуществом. Go + AI — мэтч или удачный маркетинг ❓ 🔥 — Мэтч: агентам нужны строгие рамки 🌚 — Маркетинг: агент нагенерит приключений на любом языке 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoLive
🐸 Библиотека Go-разработчика #GoGiggle
✅ Красивые таблицы в Go Иногда данные хочется вывести не просто строками в консоль, а в аккуратной читаемой таблице. Чтобы не изобретать велосипеды с fmt.Printf и ручными отступами, можно взять библиотеку tabby. Что умеет — Форматировать данные в консольные таблицы. — Поддерживает выравнивание колонок. — Позволяет строить вложенные таблицы (nested). Как использовать: t := tabby.New() t.AddHeader("ID", "Name", "Age") t.AddLine(1, "Alice", 23) t.AddLine(2, "Bob", 30) t.Print() Вывод: ID Name Age 1 Alice 23 2 Bob 30 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoToProduction
MWS проведет онлайн-митап для Go-разработчиков. 11 августа в 15:00 подключайся к эфиру: тебя ждут доклады экспертов и ответы на вопросы участников. В программе митапа: — «Построение агентов на A2A с изолированным исполнением на Go» от MWS DevRails; — «Как разрабатывать эффективные и экономичные Kubernetes-операторы на Go» от Cloud.ru; — «Точный Rate Limiting на API Gateway в мульти-ЦОД инфраструктуре» от MWS Octapi; — «Взросление OpenAPI-кодогенерации» от MWS Cloud Platform. Узнай больше о докладах, регистрируйся и добавляй в календарь по ссылке. Реклама. О рекламодателе | Сделано в WOWBLOGGER
🫣 Почему for range иногда работает не так, как ожидаешь for range выглядит простой конструкцией, но именно с ним связано множество неочевидных ошибок. Разберём три самые распространённые. 1. Переменная цикла содержит копию элемента При обходе слайса значение элемента записывается в переменную цикла: users := []User{ {Name: "Alice"}, {Name: "Bob"}, } for _, user := range users { user.Name = strings.ToUpper(user.Name) } Исходный слайс не изменится. user — это копия структуры, а не сам элемент. ➡️ Если нужно изменить данные, работайте через индекс: for i := range users { users[i].Name = strings.ToUpper(users[i].Name) } Для слайса указателей поведение будет другим: копируется указатель, а не объект, на который он указывает. 2. Адрес переменной цикла — не адрес элемента Такой код встречается довольно часто: var result []*User for _, user := range users { result = append(result, &user) } Начиная с Go 1.22 при использовании := каждая итерация получает собственную переменную цикла, поэтому указатели больше не будут ссылаться на одну и ту же переменную, как это происходило раньше. Но &user всё равно указывает на копию элемента, а не на элемент исходного слайса. ➡️ Если нужны адреса элементов, используйте индекс: for i := range users { result = append(result, &users[i]) } Если же переменная объявлена заранее и используется присваивание =, она по-прежнему переиспользуется между итерациями. 3. Изменение коллекции во время обхода Для слайсов выражение после range вычисляется один раз — до начала цикла. Поэтому количество итераций определяется исходной длиной слайса. numbers := []int{1, 2, 3} for _, n := range numbers { numbers = append(numbers, n) } Добавленные элементы в текущий обход автоматически не попадут. Кроме того, append может выделить новый underlying array, поэтому изменять слайс во время обхода стоит с осторожностью. ➡️ С map правила другие: for key := range cache { delete(cache, key) } Удалять элементы во время обхода разрешено. А вот элементы, добавленные в процессе итерации, могут как попасть в текущий обход, так и быть пропущены — спецификация этого не гарантирует. Порядок обхода map также не определён. И помните: одновременно читать и изменять map из разных горутин без синхронизации нельзя. for range скрывает немало деталей реализации. Если помнить, что переменная цикла часто содержит копию элемента, а поведение зависит от типа коллекции, многих неприятных ошибок удастся избежать. 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoToProduction
👨💻 Команды терминала, которые должен знать каждый разработчик Многие знакомы с cd, ls, pwd, но под капотом терминала — море полезных шорткатов и трюков. Вот список тех, которые экономят время, исправляют ошибки и упрощают работу: 🔴 Запуск предыдущей команды — !! Бывает забываешь написать sudo, тогда можно просто sudo !! 🔴 Заменить очепятку и выполнить команду заново — ^old^new 🔴 Заменить все вхождения в команде — !!:gs/old/new/ 🔴 Поиск по тексту в файлах — grep -R "pattern" . 🔴 Открыть последнюю команду в редакторе для редактирования — fc 🔴 Проверка доступности порта — nc -zv <host> <port> 🔴 Проверить чем занят порт — lsof -i :<port> 🐸Библиотека Go-разработчика #GoToProduction
✏️ Batch Insert в GORM. Не вставляйте записи по одной Одна из самых частых ошибок при работе с GORM выглядит так: for _, user := range users { db.Create(&user) } Если в массиве 10 000 элементов, приложение отправит 10 000 отдельных INSERT-запросов. ✅ Гораздо эффективнее вставлять записи пачкой: db.Create(&users) GORM автоматически разобьёт данные на батчи, если это потребуется. 💡 Если же размер батча нужно контролировать самостоятельно, используйте CreateInBatches: db.CreateInBatches(users, 1000) Например, при 10 000 записей и размере батча 1000 будет выполнено всего 10 INSERT-запросов вместо 10 000. Размер пачки зависит от объёма данных, но на практике чаще всего используют значения от нескольких сотен до пары тысяч записей. Batch Insert уменьшает количество сетевых запросов, снижает нагрузку на базу данных и значительно ускоряет массовую загрузку данных практически без изменений бизнес-логики. 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoToProduction
🤔 У большинства разработчиков уже есть подписки на IDE, GitHub Copilot, Claude, ChatGPT или облачные сервисы. Логично, что обучение тоже постепенно приходит к той же модели: не покупать отдельный курс под каждую новую тему, а иметь доступ ко всей библиотеке и выбирать, что актуально именно сейчас. Такой формат недавно появился и в Proglib Academy. Вместо одного курса — доступ сразу ко всей библиотеке и новым материалам, которые появляются в подписке 😎 🔗 Подробнее 🏃♀️ Proglib Academy
Кажется, у онлайн-обучения появился формат, которого давно не хватало 👇
📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
🧑💻 gsx. JSX-стиль разметки, который компилируется в обычный Go Шаблоны в Go давно вызывают споры. html/template безопасен, templ добавил удобство, но многим, кто приходит из React, всё ещё не хватает привычного JSX. 💡 gsx предлагает другой подход: компоненты пишутся в файлах .gsx, а затем компилируются в обычный Go-код (.x.go), который проверяет компилятор. Параметры компонентов — это обычные параметры функций Go, поэтому весь контракт остаётся типизированным. Ещё одна интересная особенность — gsx.Node имеет тот же набор методов, что и templ.Component, поэтому компоненты gsx можно использовать вместе с templ без прямой зависимости от него. ➡️ Компонент выглядит так: var footer = <><hr/><small>Built with gsx</small></> component Page(children gsx.Node) { <main>{children}</main> {footer} } ➡️ Для знакомства достаточно установить CLI и создать стартовый проект: go install github.com/gsxhq/gsx/cmd/gsx@latest gsx init hello-gsx --yes cd hello-gsx npm run dev Проект пока находится в статусе alpha, поэтому использовать его в production ещё рано. Но если вам нравится JSX и вы разрабатываете SSR на Go, gsx определённо стоит попробовать. 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика
Займи слот ИТ-Пикником от Т-Банка 8 августа — время отложить ноутбуки и встретиться офлайн на ИТ-Пикнике от Т-Банка в музее-заповеднике «Коломенское». Вот сколько всего запланировано: — научпоп-лекции; — мастер-классы; — дискуссии об ИИ и больших языковых моделях; — доклады о кибербезопасности; — примеры, как данные из логов становятся решениями; — много музыки — Сream Soda, IOWA, LAB Антона Беляева и другие артисты. Бери с собой друзей, супругов и детей — каждый найдет себе что-то по душе. Зарегистрироваться и узнать больше можно здесь
💡 5 приёмов поиска утечек горутин в Go Утечки горутин — скрытая проблема, которая со временем приводит к росту потребления памяти, деградации производительности и неожиданным падениям. В отличие от «обычных» багов, такие ошибки долго не проявляют себя, а в продакшене отлавливать их уже поздно. Ниже 5 рабочих приёмов, которые помогут держать горутины под контролем. 1. Мониторинг количества горутин Запуск фоновой задачи, которая периодически считывает runtime.NumGoroutine() и сравнивает с базовым уровнем — если количество горутин выросло выше порога, сигнализировать (лог, алерт). go func() { for range ticker.C { n := runtime.NumGoroutine() if n > base+50 { // ваш порог log.Printf("горутин многовато: %d (base %d)", n, base) } } }() 2. Трассировка с помощью go tool trace При сложных сценариях запускают трассировку жизненного цикла горутин: когда они создаются, когда завершаются, как взаимодействуют. func main() { f, _ := os.Create("trace.out") defer f.Close() _ = trace.Start(f) defer trace.Stop() for i := 0; i < 10; i++ { go func() { time.Sleep(500 * time.Millisecond) }() } time.Sleep(2 * time.Second) } go run . # создаст trace.out go tool trace trace.out 3. Контекстная отмена Важно проксировать контекст через цепочку вызовов (например, в HTTP-хендлерах). Когда клиент прерывается или таймаут срабатывает — все дочерние горутины получают сигнал отмены и должны корректно завершаться. func worker(ctx context.Context, jobs <-chan int) { for { select { case <-ctx.Done(): log.Println("worker: cancelled") return case j, ok := <-jobs: if !ok { return } _ = j // делаем работу } } } func main() { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() jobs := make(chan int) go worker(ctx, jobs) go func() { // имитация продьюсера for i := 0; i < 100; i++ { select { case <-ctx.Done(): close(jobs) return case jobs <- i: } } }() time.Sleep(3 * time.Second) } 4. Интеграция goleak в тесты В тестовой среде использовать goleak.VerifyTestMain или goleak.VerifyNone (внутри тестов) для автоматического обнаружения оставшихся горутин. Это помогает не допустить утечки до продакшена. func TestMain(m *testing.M) { // глобальная проверка goleak.VerifyTestMain(m) } func TestNoLeaks(t *testing.T) { defer goleak.VerifyNone(t) // Демонстрация «правильной» горутины done := make(chan struct{}) go func() { time.Sleep(10 * time.Millisecond) close(done) }() <-done } 5. Graceful shutdown При завершении сервера или приложения — ждать, пока работающие операции завершатся, использовать таймауты, отслеживать завершение горутин. Эти паттерны не заменяют внимательного дизайна кода, но дают страховку 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoDeep
😑 Иногда забываешь синтаксис defer, select, WaitGroup или как объявить слайс? Необязательно каждый раз идти в документацию. Нашли удобную шпаргалку — на одной странице собраны самые востребованные конструкции языка: переменные, функции, структуры, интерфейсы, горутины, каналы, обработка ошибок, методы, указатели и многое другое ✅ 🔗 Ссылка 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoDeep
🧑💻 Почему каждому запросу в GORM нужен context.Context Во многих примерах можно увидеть такой код: db.Find(&users) Для небольших проектов это работает. Но в production почти всегда стоит выполнять запросы с context.Context. Если запрос к базе данных зависнет или окажется слишком долгим, Context позволяет отменить его по таймауту или при завершении HTTP-запроса ✅ 🔴 Самый простой вариант — задать таймаут: ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() err := db.WithContext(ctx).Find(&users).Error Если запрос не успеет выполниться за две секунды, драйвер базы данных попытается отменить его, а GORM вернёт ошибку. 🔴 В HTTP-приложениях ещё лучше использовать контекст самого запроса: func GetUsers(w http.ResponseWriter, r *http.Request) { var users []User if err := db.WithContext(r.Context()).Find(&users).Error; err != nil { // ... } } Если клиент закроет соединение или сервер отменит запрос, операция в базе тоже будет прервана. Context стоит использовать практически во всех серверных приложениях: HTTP API, gRPC, фоновых задачах и сервисах, работающих с внешними ресурсами ✅ Это позволяет избежать бесконечно выполняющихся запросов и делает приложение устойчивее к сбоям. 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoToProduction
💡 Дженерик-методы в Go 1.27. Цепочки вызовов без функций уровня пакета Если вы писали API на дженериках, то наверняка сталкивались с этим ограничением. До Go 1.27 метод не мог объявить собственный параметр типа. Из-за этого операции вроде Map приходилось выносить в функции уровня пакета, а вместо привычных цепочек вызовов использовать отдельные функции. 🅰️ В Go 1.27 это ограничение сняли. Теперь методы могут объявлять собственные параметры типа, благодаря чему API становится естественнее, а код — чище и удобнее для чтения 😧 Особенно это пригодится авторам библиотек, fluent API, builder-паттернов и различных коллекций: операции преобразования можно размещать непосредственно на типе, а не рядом с ним. ⚠️ Но есть важное ограничение. Интерфейсы по-прежнему не могут объявлять методы с параметрами типа, поэтому обобщённый метод нельзя использовать для реализации метода интерфейса. Это осознанное решение авторов Go, а не временное ограничение. Go 1.27 ожидается в августе 2026 года, а новую возможность уже можно попробовать в Release Candidate 🔗 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoLive
📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
❓ Как ограничить число одновременных запросов к внешнему API? Какой примитив возьмёте и почему Вопрос с ловушкой прямо в формулировке — и на ней спотыкается половина кандидатов. Подсказка: прежде чем называть примитив, спросите — а что именно ограничиваем? «Не больше 10 одновременно» и «не больше 100 в секунду» — две разные задачи с разными инструментами. Перепутаете — ответите не на тот вопрос. Дальше просто: для «одновременно» есть классический примитив, который в Go делается на одном канале особого типа (почему именно такого — тоже любят спросить). А в проде берут готовую обёртку из golang.org/x/... — тот же механизм, но с ошибками, Wait и отменой через контекст. ➡️ Как называется примитив, почему канал именно chan struct{} и что за обёртка — полный разбор 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #ReadySetGo