TGViewer
Channel Public Channel
Библиотека Go-разработчика | Golang

Библиотека Go-разработчика | Golang

@goproglib

Все самое полезное для Go-разработчика в одном канале.

Учиться у нас: clc.to/qaSdww

По рекламе: @tproger_sales_bot

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0

#WXSSA
Subscribers
24.1K
Photos
2.8K
Videos
54
Links
5.4K

Showing posts older than #7456 · Back to latest

Older Posts 20 shown
Post #7455 5.84K
🔥 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
  • 👏 12
  • 😢 8
  • 👍 7
  • ❤ 3
Post #7454 5.5K
❓ Что на самом деле лежит внутри слайса

Слайс — не массив, а небольшая структура:


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
  • ❤ 9
  • 🥱 6
  • 👍 3
  • 😁 1
  • 🌚 1
Post #7453 5.19K
🤷‍♂️ Почему Go удобен для AI-кодинга

Команда Go выпустила разбор о том, почему язык хорошо подходит для работы с AI-агентами.

Ключевой аргумент — Go легко проверять:

⬆️gofmt стандартизирует код
⬆️компилятор ловит ошибки
⬆️типов и выдуманные API
⬆️тесты и fuzzing встроены в
⬆️toolchain govulncheck проверяет
⬆️уязвимые зависимости
⬆️go fix и gopls помогают с
⬆️рефакторингом

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

Go + AI — мэтч или удачный маркетинг ❓

🔥 — Мэтч: агентам нужны строгие рамки
🌚 — Маркетинг: агент нагенерит приключений на любом языке

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoLive
  • 🔥 47
  • 🌚 18
  • ❤ 4
  • 🤔 1
  • 👾 1
Post #7451 4.53K
✅ Красивые таблицы в 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
  • 🔥 18
  • 👍 5
  • 🤔 1
  • 💯 1
Post #7450 4.28K
MWS проведет онлайн-митап для Go-разработчиков. 
11 августа в 15:00 подключайся к эфиру: тебя ждут доклады экспертов и ответы на вопросы участников. 

В программе митапа:

— «Построение агентов на A2A с изолированным исполнением на Go» от MWS DevRails;
— «Как разрабатывать эффективные и экономичные Kubernetes-операторы на Go» от Cloud.ru; 
— «Точный Rate Limiting на API Gateway в мульти-ЦОД инфраструктуре» от MWS Octapi;
— «Взросление OpenAPI-кодогенерации» от MWS Cloud Platform.

Узнай больше о докладах, регистрируйся и добавляй в календарь по ссылке.

Реклама. О рекламодателе | Сделано в WOWBLOGGER
  • 🌚 3
  • 👏 2
  • 🥱 1
Post #7449 3.93K
🫣 Почему 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
  • 👍 11
  • ❤ 7
  • 🥰 1
  • 😁 1
  • 👾 1
Post #7448 3.84K
👨‍💻 Команды терминала, которые должен знать каждый разработчик

Многие знакомы с cd, ls, pwd, но под капотом терминала — море полезных шорткатов и трюков. Вот список тех, которые экономят время, исправляют ошибки и упрощают работу:

🔴 Запуск предыдущей команды — !!

Бывает забываешь написать sudo, тогда можно просто sudo !!

🔴 Заменить очепятку и выполнить команду заново — ^old^new

🔴 Заменить все вхождения в команде — !!:gs/old/new/

🔴 Поиск по тексту в файлах — grep -R "pattern" .

🔴 Открыть последнюю команду в редакторе для редактирования — fc

🔴 Проверка доступности порта — nc -zv <host> <port>

🔴 Проверить чем занят порт — lsof -i :<port>

🐸Библиотека Go-разработчика

#GoToProduction
  • ❤ 17
  • 🤩 1
Post #7447 3.67K
✏️ 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
  • 👍 12
  • 🤔 3
  • 🌚 2
  • ❤ 1
  • 🥱 1
Post #7446 3.17K

Forwarded from Proglib.academy | IT-курсы

🤔 У большинства разработчиков уже есть подписки на IDE, GitHub Copilot, Claude, ChatGPT или облачные сервисы.

Логично, что обучение тоже постепенно приходит к той же модели: не покупать отдельный курс под каждую новую тему, а иметь доступ ко всей библиотеке и выбирать, что актуально именно сейчас.


Такой формат недавно появился и в Proglib Academy. Вместо одного курса — доступ сразу ко всей библиотеке и новым материалам, которые появляются в подписке 😎

🔗 Подробнее

🏃‍♀️ Proglib Academy
  • 😁 9
  • 👍 2
  • 👏 2
  • 😢 1
  • 💯 1
Post #7445 3.46K
Кажется, у онлайн-обучения появился формат, которого давно не хватало 👇
  • 👏 2
  • 🤔 2
  • 🥱 2
  • 🙏 1
Post #7443 4.23K
🧑‍💻 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-разработчика
  • 😁 7
  • ❤ 3
  • ⚡ 1
  • 💯 1
Post #7441 3.69K
💡 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
  • 👍 10
  • ⚡ 2
  • 🤔 2
  • 😁 1
  • 👾 1
Post #7440 4.1K
😑 Иногда забываешь синтаксис defer, select, WaitGroup или как объявить слайс? Необязательно каждый раз идти в документацию.

Нашли удобную шпаргалку — на одной странице собраны самые востребованные конструкции языка: переменные, функции, структуры, интерфейсы, горутины, каналы, обработка ошибок, методы, указатели и многое другое ✅

🔗 Ссылка

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoDeep
  • 🔥 12
  • ❤ 2
  • 👍 1
Post #7439 3.94K
🧑‍💻 Почему каждому запросу в 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
  • 🥱 14
  • ❤ 6
  • 👍 6
Post #7438 4.41K
💡 Дженерик-методы в Go 1.27. Цепочки вызовов без функций уровня пакета

Если вы писали API на дженериках, то наверняка сталкивались с этим ограничением. До Go 1.27 метод не мог объявить собственный параметр типа. Из-за этого операции вроде Map приходилось выносить в функции уровня пакета, а вместо привычных цепочек вызовов использовать отдельные функции.

🅰️ В Go 1.27 это ограничение сняли. Теперь методы могут объявлять собственные параметры типа, благодаря чему API становится естественнее, а код — чище и удобнее для чтения 😧

Особенно это пригодится авторам библиотек, fluent API, builder-паттернов и различных коллекций: операции преобразования можно размещать непосредственно на типе, а не рядом с ним.


⚠️ Но есть важное ограничение. Интерфейсы по-прежнему не могут объявлять методы с параметрами типа, поэтому обобщённый метод нельзя использовать для реализации метода интерфейса. Это осознанное решение авторов Go, а не временное ограничение.

Go 1.27 ожидается в августе 2026 года, а новую возможность уже можно попробовать в Release Candidate 🔗

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoLive
  • 🔥 13
  • ❤ 4
  • 👾 2
  • 😍 1
Post #7436 4.31K
❓ Как ограничить число одновременных запросов к внешнему API? Какой примитив возьмёте и почему

Вопрос с ловушкой прямо в формулировке — и на ней спотыкается половина кандидатов.

Подсказка: прежде чем называть примитив, спросите — а что именно ограничиваем? «Не больше 10 одновременно» и «не больше 100 в секунду» — две разные задачи с разными инструментами. Перепутаете — ответите не на тот вопрос.

Дальше просто: для «одновременно» есть классический примитив, который в Go делается на одном канале особого типа (почему именно такого — тоже любят спросить). А в проде берут готовую обёртку из golang.org/x/... — тот же механизм, но с ошибками, Wait и отменой через контекст.

➡️ Как называется примитив, почему канал именно chan struct{} и что за обёртка — полный разбор

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#ReadySetGo
  • ❤ 2
  • 🔥 1
  • 🥰 1
Post #7434 3.77K
📎 В Go предложили переносимый SIMD, не привязанный к архитектуре

В трекере Go появилось предложение #78902 о переносимом SIMD API. Автор — David Chase из команды компилятора. Это второй уровень поверх той работы над SIMD, что описана в проекте #73787. Важно сразу оговорить статус. Это предложение в состоянии Active, оно ещё обсуждается и не принято.

Напомним контекст. В Go 1.26 уже появился экспериментальный пакет simd/archsimd, который включается через GOEXPERIMENT=simd. Он даёт доступ к SIMD-инструкциям конкретной архитектуры, то есть вы работаете напрямую с типами вроде Float32x8 и должны сами учитывать, что доступно на целевом процессоре. Новое предложение решает другую боль. Писать под каждую архитектуру и под каждую ширину вектора отдельно неудобно, а код получается непереносимым.

Идея в том, чтобы дать абстрактный интерфейс к SIMD-векторам, не завязанный ни на архитектуру, ни на длину вектора. Там, где инструкции есть, API работает быстро. Там, где их нет, он сохраняет переносимость за счёт эмуляции. При запуске на разных вариантах одной архитектуры библиотека сама выбирает лучший доступный набор, например переключается между AVX, AVX2 и AVX512.

В первой версии список операций небольшой. Это пересечение SIMD API для wasm и текущего amd64. Набор скромный, зато его проще эмулировать на платформах без SIMD и проще поддержать при добавлении новых архитектур. Типы названы по образцу заглавной буквы и множественного числа, например Int8s или Float64s.

Внутри одного запуска программы все векторы имеют одинаковую длину в битах, поэтому их можно переинтерпретировать методами вида x.AsFloat64s(). Маски вынесены в отдельную абстракцию, потому что архитектуры реализуют их по-разному. У типов есть методы .Masked(mask) и .Merged(valueIfFalse, mask), а сами маски комбинируются через And и Or.

Предусмотрен и спуск на уровень конкретной архитектуры через ToArch() и обратно через ToSimd(), хотя в прототипе этого пока нет. По задумке это выглядит так:
//go:build amd64

import (
"simd"
"simd/archsimd"
)

func sum(x simd.Float32s) float32 {
switch a := x.ToArch().(type) {
case archsimd.Float32x8:
a = a.AddPairsGrouped(a)
a = a.AddPairsGrouped(a)
return a.GetLo().GetElem(0) + a.GetHi().GetElem(0)
case archsimd.Float32x16:
// ...
case archsimd.Float32x4:
// ...
}
}


Под капотом код, зависящий от пакета simd, компилятор размножает на несколько вариантов под разные наборы инструкций, а функции со скрытой зависимостью превращает в диспетчеры.

Переписывание идёт рано, чтобы сохранить шанс на инлайнинг. Есть нюанс для инструментов. Сгенерированные имена содержат символ @ и недоступны из исходного кода, что может влиять на отладчики и утилиты, читающие символы объектных файлов.

Есть черновой CL 763100, где сам API лежит в simd/mocks.go и генерируется автоматически. Пробовать в проде рано, но за направлением стоит следить, если вам важна производительность на горячих циклах.

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoLive
  • 🔥 13
  • ❤ 3
  • ⚡ 1
  • 👏 1
  • 💯 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →