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 #7478 · Back to latest

Older Posts 20 shown
Post #7477 4.76K
🚨 Go 1.27 поменял encoding/json изнутри

API старого encoding/json остался прежним, но под капотом теперь работает новый движок encoding/json/v2. Для существующего кода это должно быть прозрачно — Go сохраняет старую семантику через набор compatibility-опций.

Но производительность изменилась.

В независимом бенчмарке на одинаковых данных:

🔘 Unmarshal в структуру — примерно в 1,5 раза быстрее;
🔘 Unmarshal в any — примерно в 1,5 раза медленнее;
🔘 Marshal — немного медленнее, зато заметно меньше аллокаций;
🔘 потоковая работа через новый API MarshalWrite требует значительно меньше памяти.


Самая интересная ловушка — any. Старый API разрешает дубликаты ключей JSON, поэтому новый движок не может использовать свой быстрый путь для any. В результате динамический JSON может обрабатываться медленнее.

🤩 А если перейти непосредственно на encoding/json/v2, появляются новые дефолты: дубликаты ключей и невалидный UTF-8 отклоняются, nil-слайсы и map по умолчанию кодируются иначе, а порядок ключей map не гарантируется без Deterministic.

После перехода на Go 1.27 недостаточно проверить только компиляцию. Если encoding/json находится на горячем пути — стоит прогнать свои бенчмарки. Особенно если приложение активно работает с any или map[string]any.

А encoding/json/v2 уже можно внедрять постепенно, сохраняя нужные v1-семантики через DefaultOptionsV1().

🔗 Официальный гайд по миграции encoding/json/v2

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

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

#GoLive
  • ❤ 11
  • 👍 3
  • ⚡ 2
  • 🥱 1
  • 👾 1
Post #7476 4.59K
🤩 Table driven tests в Go

Обычная история: есть функция и десять сценариев. Если писать по тесту на каждый сценарий, код быстро превращается в копипасту. Table driven подход делает один тест, а сценарии складывает в таблицу.

Вы описываете кейсы в таблице, обычно это слайс структур. Потом в цикле запускаете каждый кейс как сабтест через t.Run, чтобы у каждого сценария было имя и его можно было запустить отдельно.

🟡 Пример на простой функции:


func Split(s, sep string) []string {
return strings.Split(s, sep)
}

func TestSplit(t *testing.T) {
tests := []struct {
name string
input string
sep string
want []string
}{
{name: "simple", input: "a/b/c", sep: "/", want: []string{"a", "b", "c"}},
{name: "no sep", input: "abc", sep: "/", want: []string{"abc"}},
{name: "trailing", input: "a/b/c/", sep: "/", want: []string{"a", "b", "c", ""}},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got, tc.want) {
t.Fatalf("want %v got %v", tc.want, got)
}
})
}
}


Еще мелочь, но полезная. Внутри сабтеста t.Fatal завершает только текущий сабтест, а не весь набор, поэтому для table driven тестов это часто удобнее чем тянуть continue и пачку if.

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

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

#GoDeep
  • 👍 7
  • 🔥 2
  • 🥱 2
  • ❤ 1
  • 🥰 1
Post #7475 4.08K
🧹 t.Cleanup: уборка в Go-тестах без лишних defer

Подняли тестовую БД, создали временный файл или запустили сервер? t.Cleanup позволяет привязать очистку прямо к жизненному циклу теста.

🟡 Главный плюс — хелперы могут сами отвечать за освобождение ресурсов:


func newTestDB(t *testing.T) *sql.DB {
t.Helper()

db := openTempDB(t)
t.Cleanup(func() {
db.Close()
})

return db
}


🟡 Теперь тесту не нужно помнить про defer:


func TestUsers(t *testing.T) {
db := newTestDB(t)
// ...
}


Cleanup выполнится после завершения теста, даже если тот упал через t.Fatal. Несколько cleanup-функций выполняются в обратном порядке регистрации.

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

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

#GoToProduction
  • 👍 16
  • 🙏 2
  • 👾 2
  • ⚡ 1
Post #7474 4.48K
🤩 templ: типобезопасный HTML в Go

html/template работает со строковыми шаблонами, а templ позволяет писать HTML-компоненты прямо в .templ и превращать их в обычный Go-код.


templ Hello(name string) {
<div class="greeting">Привет, { name }</div>
}


После templ generate компонент можно использовать как обычную функцию:


view.Hello("гофер").Render(ctx, w)


📍 Плюс — типы и ошибки в компонентах проверяются при компиляции, есть автоматическое экранирование HTML.

Особенно удобно для серверного рендеринга и связки Go + htmx, когда полноценный frontend-фреймворк не нужен.

🔗 ⁠templ · ⁠GitHub

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

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

#GoToProduction
  • ❤ 6
  • 👍 6
Post #7473 4.72K
🤩 Go 1.25 больше не получает security-фиксы

19 августа вышел Go 1.27 — и по политике Go поддерживаемыми теперь остаются только 1.27 и 1.26.

Если проект всё ещё собирается на 1.25, это хороший момент для обновления. Для тех, кто пока не готов переходить на 1.27, есть актуальная ветка 1.26 с патч-релизом 1.26.7.

Проверить зависимости на известные уязвимости можно через:


govulncheck ./…


А заодно стоит посмотреть на изменения в encoding/json: в Go 1.27 появился новый encoding/json/v2, а старый пакет теперь работает поверх его реализации.

🔗 Источники: ⁠Go Release History · ⁠Go Vulnerability Database

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

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

#GoLive
  • 👍 8
  • 😢 3
  • 💯 2
Post #7472 4.64K
🐳 Go в Kubernetes мог зря конкурировать за CPU — с Go 1.25 это изменилось

До Go 1.25 рантайм ориентировался на CPU всей машины. Поэтому pod с лимитом в 2 CPU на 64-ядерной ноде мог получить GOMAXPROCS=64.

Linux при превышении CPU limit начинал throttling — процесс мог полностью приостанавливаться на оставшуюся часть периода. Это особенно неприятно для tail latency.

🌞 В Go 1.25 рантайм на Linux начал учитывать CPU limit из cgroup:

runtime.GOMAXPROCS(0)


Например, pod с лимитом в 2 CPU → GOMAXPROCS будет 2. Значение также периодически пересчитывается, если cgroup limit меняется.

⚠️ Но есть ловушка: если вы вручную задаёте GOMAXPROCS через env или:


runtime.GOMAXPROCS(8)


автоматическая настройка отключается.

🔘 То же самое касается старого automaxprocs: после перехода на Go 1.25+ стоит проверить, нужен ли он вообще. И ещё нюанс: Go ориентируется на CPU limit, а не CPU request.

📌 Если Go-сервис живёт в Kubernetes, проверить GOMAXPROCS после обновления Go — довольно дешёвый способ найти старую настройку, которая больше не нужна.

🔗 Источник

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

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

#GoDeep
  • ❤ 5
  • 👏 4
  • 👾 3
  • 😢 1
Post #7471 4.65K
📎 Библиотека анимаций для терминала

Для тех, кто занимается разработкой текстовых интерфейсов на Go, есть интересный инструмент — библиотека sysc-Go.

В библиотеке доступны разные категории эффектов: от классического цифрового дождя в стиле «Матрицы» и пламени Doom до красочных фейерверков и подводных анимаций с рыбой.

Есть и текстовые эффекты, которые оживляют ASCII-арт — например, огненный текст, эффекты типографики с имитацией печатной машинки или вращающиеся кольцевые анимации.


Чистая реализация на Go без зависимостей, удобный CLI-интерфейс с выбором и просмотром всех доступных эффектов, а также встроенный ASCII-редактор с живым предпросмотром.

➡️ Анимировать терминал

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

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

#GoToProduction
  • 👾 5
  • 😁 1
  • 🤔 1
  • 🤩 1
Post #7470 4.53K
Charm: красивые TUI-приложения на Go

Если fmt.Println уже кажется слишком скучным, посмотрите на экосистему ⁠Charm 🤩

🤩 Bubble Tea — фреймворк для интерактивных TUI на Go
🤩 Lip Gloss — стили, цвета, рамки и layout
🤩 Bubbles — готовые компоненты: списки, спиннеры, input и другие
🤩 Gum — интерактивные элементы для shell-скриптов без Go

Например, меню выбора в bash:

gum choose "deploy" "rollback" "cancel"


А если хочется написать полноценный терминальный интерфейс — можно собрать его на Bubble Tea.

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

🐸 Библиотека Go-разработчика
  • ❤ 11
  • 🥰 3
  • 🙏 2
  • 😍 2
  • 👍 1
Post #7468 4.94K
🤩 Go tip: вшивайте файлы прямо в бинарник через go:embed

Нужны шаблоны, миграции или небольшая статика, но не хочется таскать их рядом с бинарником?


import "embed"

//go:embed templates/*.html
var templatesFS embed.FS


Дальше embed.FS можно использовать с html/template, text/template или net/http.


templates.ParseFS(templatesFS, "templates/*.html»)


Можно вшить и отдельный файл:


//go:embed version.txt
var version string


📌 Файлы попадают в программу при сборке. Изменили ресурс — пересобирайте бинарник.

Для шаблонов, миграций и небольшой статики — отличный вариант. Для огромных ассетов — уже стоит подумать о другом подходе.

⁠🔗 Документация

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

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

#GoToProduction
  • 👍 7
  • 🤩 3
  • ❤‍🔥 2
  • 🥱 1
Post #7467 4.61K
✏️ Расстояния между единицами: находим нужный паттерн

Дан массив нулей и единиц, нужно проверить, что между любыми двумя единицами находится минимум k нулей. Звучит элементарно, но в реализации легко споткнуться.

Массив [1,0,0,0,1,0,0,1] при k=2 валиден: между первой и второй единицей три нуля (достаточно), между второй и третьей — два нуля (достаточно). А вот [1,0,1,0,0,1] при k=2 — нет, потому что первые две единицы разделены только одним нулём.

Запоминаем позицию последней найденной единицы. Когда встречаем новую, проверяем расстояние до неё и сразу обновляем позицию.

Это будет один проход по массиву:


func kLengthApart(nums []int, k int) bool {
lastPos := -k - 1

for i := 0; i < len(nums); i++ {
if nums[i] == 1 {
if i - lastPos - 1 < k {
return false
}
lastPos = i
}
}
return true
}


Результат: O(n) время, O(1) память.

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

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

#ReadySetGo
  • ❤ 6
  • 👾 4
  • 👍 1
  • 💯 1
Post #7466 4.58K
🛠️ sqlc: пишешь SQL → получаешь типобезопасный Go

Вместо ORM и ручного Scan можно оставить SQL как есть, а Go-код сгенерировать:

-- name: GetAuthor :one
SELECT id, name, bio
FROM authors
WHERE id = $1;


sqlc generate


После генерации:

author, err := queries.GetAuthor(ctx, id)


sqlc проверяет запросы относительно схемы и генерирует типизированные структуры и методы.

Поддерживаются PostgreSQL, MySQL и SQLite.

⚡️ Документация

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

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

#GoToProduction
  • 👍 14
  • 🥱 7
  • ❤ 3
  • 🤔 3
Post #7465 4.47K
🛡 Go tip: не открывайте локальный сервис наружу случайно

Если HTTP-сервис должен быть доступен только на вашей машине, слушайте 127.0.0.1, а не 0.0.0.0:


srv := &http.Server{
Addr: "127.0.0.1:8001",
}


127.0.0.1 — только локальный интерфейс.

А:


Addr: "0.0.0.0:8001»


означает прослушивание всех IPv4-интерфейсов.

📌 Для локальных админок, debug-сервисов и dev-инструментов это простая настройка, которую легко забыть — и случайно выставить сервис в сеть.

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

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

#GoToProduction
  • ❤ 9
  • 🥱 8
  • 👍 3
  • 👏 2
  • 🎉 1
Post #7464 4.4K
💡 Как append растит слайс

Все знают, что append добавляет элемент в слайс. А вот что происходит, когда место в массиве кончилось, знают не всегда, и как раз тут прячется пара неожиданностей.

🔵 Пока есть запас

У слайса есть len и cap. Пока len меньше cap, append дописывает элемент прямо в тот же массив и возвращает слайс, который смотрит туда же. Никакого копирования, дёшево. Именно поэтому два слайса, делящие один массив, могут внезапно перетирать данные друг друга при append в один из них.

🔵 Когда запас кончился

Как только cap исчерпан, рантайм выделяет новый массив побольше, копирует туда старые элементы и возвращает слайс уже на новую память. С этого момента старый и новый слайс не связаны, и запись в один не видна в другом. Отсюда правило, которое многих спасало от багов. Всегда присваивайте результат обратно.


s = append(s, x)


🔵 На сколько растёт

Точный коэффициент это деталь реализации, которая менялась от версии к версии, поэтому закладываться на конкретное число не стоит. Грубый ориентир такой. Маленькие слайсы растут примерно вдвое, большие прибавляют около четверти за раз, а переход между режимами сглажен в районе нескольких сотен элементов. Смысл в том, чтобы амортизировать стоимость и не копировать массив на каждом добавлении.

Если вы заранее знаете примерный размер, выделяйте вместимость сразу.


s := make([]int, 0, n)
for i := 0; i < n; i++ {
s = append(s, f(i))
}

Так вы избегаете череды перевыделений и копирований, а заодно снимаете нагрузку со сборщика мусора. На горячих циклах это заметно.

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

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

#GoDeep
  • 👍 6
  • 🥱 5
  • ❤ 2
  • ❤‍🔥 1
Post #7463 4.14K
⚙️ Go tip: errgroup вместо ручного управления группой горутин

Нужно параллельно выполнить несколько задач, остановиться при ошибке и ограничить количество одновременно работающих операций?

Вместо WaitGroup + канала ошибок можно использовать golang.org/x/sync/errgroup:


g, ctx := errgroup.WithContext(ctx)
g.SetLimit(8)

for _, url := range urls {
g.Go(func() error {
return fetch(ctx, url)
})
}

if err := g.Wait(); err != nil {
return err
}


WithContext отменяет контекст при первой ошибке, SetLimit(8) держит максимум 8 активных горутин, а Wait() возвращает ошибку.

🔗 Источник

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

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

#GoToProduction
  • 👍 18
  • 🥱 5
  • ❤‍🔥 2
  • 🤩 2
Post #7462 4.49K
🔎 Go tip: откуда в проекте взялась эта зависимость?

Нашли незнакомый модуль в go.mod и не понимаете, кто его подтянул?

Поможет:


go mod why -m golang.org/x/text


Go покажет цепочку зависимостей, из-за которой модуль оказался нужен проекту.

Например:


your-project

github.com/example/api

golang.org/x/text


📌 Полезно перед чисткой go.mod, обновлением зависимостей или разбором supply chain.

А если нужно посмотреть, какие модули вообще используются, пригодится:


go mod graph


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

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

#GoToProduction
  • 👍 12
  • 🔥 2
  • 🎉 2
  • 🥱 1
Post #7459 4.31K
⏱️ testing/synctest: тестируем время и горутины без Sleep на секунды

Тесты конкурентного кода часто либо долго выполняются из-за реального времени, либо флакают из-за гонок.
В Go 1.25 появился стабильный testing/synctest, который позволяет запускать тест в изолированном bubble с виртуальным временем.


func TestTimeout(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
ctx, cancel := context.WithTimeout(
context.Background(),
time.Hour,
)
defer cancel()

<-ctx.Done()

if ctx.Err() != context.DeadlineExceeded {
t.Fatal("timeout did not expire")
}
})
}


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

А synctest.Wait() позволяет дождаться, пока конкурентная работа в bubble завершится или перейдёт в состояние ожидания.

📌 synctest был экспериментом в Go 1.24, а с Go 1.25 входит в стандартную библиотеку.

🔗 Источник

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

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

#GoToProduction
  • 🤔 5
  • ⚡ 1
  • ❤ 1
  • 😍 1
  • 👾 1
Post #7458 4.09K
💡 Что внутри у any

Раньше мы разбирали, что обычный интерфейс это структура из двух указателей, на таблицу типа и на данные. Пустой интерфейс, он же any, устроен похоже, но проще, и об этом стоит знать отдельно.

🟢 Две разные структуры

Непустой интерфейс в рантайме это iface. Внутри у него itab, где лежат тип интерфейса, конкретный тип, хеш и таблица методов. У пустого интерфейса методов нет, значит и таблица методов ему не нужна. Поэтому any представлен другой, более лёгкой структурой, eface.


type eface struct {
_type *_type
data unsafe.Pointer
}


Здесь _type это указатель на описание конкретного типа, а data это указатель на само значение. Никакого itab и списка методов, потому что вызывать через any всё равно нечего. Из-за этого приведение типа и type switch по any сводятся к сравнению указателя на тип, без похода в таблицу методов.

🟢 Классическая ловушка с nil

Из устройства следует известный подвох. Интерфейс равен nil, только когда оба поля пустые, и тип, и данные. Стоит завернуть в интерфейс нетипизированный `nil`-указатель, и получится интерфейс, у которого тип уже не пустой.


var p *MyError = nil
var err error = p
fmt.Println(err == nil) // false


Тип внутри err теперь *MyError, поэтому сравнение с nil даёт false, хотя указатель внутри нулевой. Отсюда практичное правило. Возвращайте из функций именно nil литералом, а не заранее объявленную типизированную переменную, если хотите, чтобы вызывающий код честно увидел nil.

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

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

#GoDeep
  • ❤ 6
  • 👍 3
Post #7456 4.38K
⏱️ Go 1.27: ещё одно изменение, которое стоит проверить в старом коде

В прошлом посте разбирали дженерик-методы, которые появятся в Go 1.27. Но в релизе есть и менее заметное изменение — окончательно убирают GODEBUG=asynctimerchan.

Этот переключатель временно возвращал старое поведение time.Timer и time.Ticker из Go 1.22 и более ранних версий.
С Go 1.27 таймерные каналы окончательно становятся синхронными.

Поэтому старый код вроде:


if !t.Stop() {
<-t.C
}
t.Reset(d)


теперь стоит пересмотреть: ручное вычитывание канала перед Reset больше не требуется и может привести к блокировке.

📌 Если уже готовитесь к Go 1.27, проверьте по проекту:

⬆️ asynctimerchan → удалить
⬆️ Stop() + <-t.C → проверить
⬆️ Stop() + Reset() → проверить

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

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

#GoLive
  • 👍 6
  • ❤ 4
  • 🥱 2
  • 🔥 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 →