😱 Если ваш продукт не умеет отдавать данные в формате, понятном AI-агенту, то вас просто не существует
Скрипт не будет кликать по красивым кнопкам в браузере, он уйдёт к конкуренту с нормальным API. Перестроить архитектуру под машинных клиентов — это уже не хайп, а необходимое условие сохранения конкурентоспособности.
Как адаптировать продукт и не исчезнуть из выдачи:
— интегрировать
— научиться контролировать стоимость (лимиты, кэш, роутинг между моделями);
— настроить AgentOps: трейсинг, логирование и отлов регрессий.
Всё это ждёт вас на обновлённом курсе «Разработка AI-агентов». Мы специально сделали фокус на утилитарном инжиниринге и production-ready решениях.
Кстати, до 29 марта можно забрать курс с большой скидкой, и стоит поторопиться — мест на потоке всё меньше.
Зафиксировать цену и начать деплоить агентов без слива бюджета 👈
Скрипт не будет кликать по красивым кнопкам в браузере, он уйдёт к конкуренту с нормальным API. Перестроить архитектуру под машинных клиентов — это уже не хайп, а необходимое условие сохранения конкурентоспособности.
Как адаптировать продукт и не исчезнуть из выдачи:
— интегрировать
MCP и A2A-взаимодействие, чтобы агенты могли вас читать;— научиться контролировать стоимость (лимиты, кэш, роутинг между моделями);
— настроить AgentOps: трейсинг, логирование и отлов регрессий.
Всё это ждёт вас на обновлённом курсе «Разработка AI-агентов». Мы специально сделали фокус на утилитарном инжиниринге и production-ready решениях.
Кстати, до 29 марта можно забрать курс с большой скидкой, и стоит поторопиться — мест на потоке всё меньше.
Зафиксировать цену и начать деплоить агентов без слива бюджета 👈
🥱17😁3🤔2👍1
🔄 GoLand 2026.1 вышел
С пылу с жару — GoLand 2026.1. Несколько полезных обновлений для Go-разработчиков.
Синтаксические обновления для Go 1.26. IDE теперь сама находит устаревший код и предлагает перейти на новый синтаксис. Поддерживаются два паттерна: создание указателей через
Git worktrees. Теперь можно работать с несколькими ветками одновременно без переключения контекста. Удобно для hotfix-ов или когда AI-агенту нужна отдельная ветка.
Больше AI-агентов. Помимо Junie и Claude Agent, добавлена поддержка GitHub Copilot, Cursor и других агентов через Agent Client Protocol (ACP). Устанавливаются в один клик через новый ACP Agent Registry.
Terraform Stacks. Базовая поддержка работы со стеками прямо в IDE: навигация по компонентам, автодополнение, создание деплойментов.
Wayland по умолчанию на Linux. Улучшены рендеринг и обработка ввода. Если Wayland недоступен, IDE автоматически переходит на X11.
Code With Me уходит. Начиная с 2026.1 плагин исключён из поставки IDE. Он доступен в JetBrains Marketplace как отдельный плагин, но 2026.1 станет последней версией с официальной поддержкой сервиса.
➡️ Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoLive
С пылу с жару — GoLand 2026.1. Несколько полезных обновлений для Go-разработчиков.
Синтаксические обновления для Go 1.26. IDE теперь сама находит устаревший код и предлагает перейти на новый синтаксис. Поддерживаются два паттерна: создание указателей через
new() и типобезопасное разворачивание ошибок через errors.AsType. Применить изменения можно сразу по всему проекту через меню Refactor → Update Syntax или через Search Everywhere. Перед применением показывается diff-превью каждого изменения.Git worktrees. Теперь можно работать с несколькими ветками одновременно без переключения контекста. Удобно для hotfix-ов или когда AI-агенту нужна отдельная ветка.
Больше AI-агентов. Помимо Junie и Claude Agent, добавлена поддержка GitHub Copilot, Cursor и других агентов через Agent Client Protocol (ACP). Устанавливаются в один клик через новый ACP Agent Registry.
Terraform Stacks. Базовая поддержка работы со стеками прямо в IDE: навигация по компонентам, автодополнение, создание деплойментов.
Wayland по умолчанию на Linux. Улучшены рендеринг и обработка ввода. Если Wayland недоступен, IDE автоматически переходит на X11.
Code With Me уходит. Начиная с 2026.1 плагин исключён из поставки IDE. Он доступен в JetBrains Marketplace как отдельный плагин, но 2026.1 станет последней версией с официальной поддержкой сервиса.
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13🥱3👍1
Есть парсер логов. Работает месяцами. Однажды в лог прилетает одна аномальная строка: 100 КБ без символа переноса.
bufio.Scanner читает файл в цикле. Программа не паникует, не выбрасывает ошибку в stderr, не зависает. Просто эта строка не попадает в обработку. По умолчанию
Scanner не обработает токен длиннее bufio.MaxScanTokenSize, но какое ожидаемое поведение при переполнении?📍 Навигация: Вакансии • Задачи • Собесы
#ReadySetGo
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2
В Go 1.21 вывод типов заметно улучшился: компилятор научился автоматически подбирать типовые параметры дженерик-функции, когда она используется в присваивании или возвращается из другой функции. Но, как оказалось, это работало не везде одинаково.
Но, присваивание дженерик-функции полю структуры через
= компилятор обрабатывает корректно, а то же самое через литерал структуры нет.Вот конкретный пример:
type S struct{ f func(int) }
func g[T any](T) {}
func _(s S) {
s.f = g // ok
s = S{f: g} // error: cannot use generic function g without instantiation
s = S{f: g[int]} // ok — но зачем, если тип и так известен?
}То же самое касается элементов массивов, слайсов, мап и отправки в каналы — паттерн одинаковый: через индекс работает, через литерал — нет.
Во всех этих случаях тип левой стороны присваивания полностью известен во время компиляции, так что вывод типового параметра однозначен. Отсутствие вывода это неожиданное поведение, заставляющее разработчика писать лишний шум вроде
g[int] там, где он очевиден.📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3
Разработчик сравнил практически все распространённые подходы к конкатенации строк в Go и прогнал их через бенчмарки. Два сценария: фиксированное число аргументов (например, сборка cache key) и переменное (динамические SQL-условия и т.п.).
Что тестировалось
+, +=, fmt.Sprintf, fmt.Sprint, strings.Join, bytes.Buffer, strings.Builder — последние два с предварительной аллокацией через .Grow() и без.Фиксированные аргументы
В сценарии с фиксированным числом аргументов победителем оказался
strings.Builder с предварительной аллокацией, следом + оператор и strings.Join. Все трое с минимальным числом аллокаций и низким потреблением памяти. Проще говоря, привычный + здесь вполне нормален и не нужно его усложнять.// Просто и быстро для фиксированных аргументов
func BuildCacheKey(id, name, region string) string {
return id + "#" + name + "#" + region
}
Переменные аргументы
При переменном числе аргументов лидируют
strings.Builder с .Grow() и strings.Join — оба показали одинаково хорошие результаты по времени, памяти и числу аллокаций. += в цикле оказался катастрофически медленным: на 256 аргументах он требует 255 аллокаций против 1 у Join.// Плохо: O(n) аллокаций
func bad(ss []string) string {
result := ss[0]
for _, s := range ss[1:] {
result += "#" + s // новая аллокация на каждой итерации
}
return result
}
// Хорошо: 1 аллокация
func good(ss []string) string {
return strings.Join(ss, "#")
}
// Хорошо: 1 аллокация, максимум скорости
func best(ss []string) string {
var length int
for _, s := range ss {
length += len(s) + 1
}
var b strings.Builder
b.Grow(length)
b.WriteString(ss[0])
for _, s := range ss[1:] {
b.WriteString("#")
b.WriteString(s)
}
return b.String()
}
Практические рекомендации:
- Фиксированное число строк → просто
+, не думайте об этом- Переменное число строк →
strings.Join как дефолт, strings.Builder + .Grow() если критична производительность-
fmt.Sprintf / fmt.Sprint → только для форматирования, не для конкатенации-
bytes.Buffer → медленнее strings.Builder почти везде, смысла нет-
+= в цикле → никогдаfmt.Sprintf медленнее всех в фиксированном сценарии, а strings.Join оказался неожиданно быстрым. Сам автор признаётся, что использовал Sprintf по привычке из-за удобной форматной строки — и зря.Ничего революционного, но полезно иметь под рукой как шпаргалку, когда кто-то в ревью спрашивает «а почему не Sprintf?».
📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍8🔥1
📰 Дайджест материалов
Последний дайджест марта.
— QA в 2026 это уже не просто
— Markdown-CMS на Go без базы данных
— Миграция на Fiber v3
— Kafka выстрелила в прод в 7 утра
— GoLand 2026.1
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoLive
Последний дайджест марта.
— QA в 2026 это уже не просто
— Markdown-CMS на Go без базы данных
— Миграция на Fiber v3
— Kafka выстрелила в прод в 7 утра
— GoLand 2026.1
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1👾1
🐳 Плавающие теги в Docker
Большинство Dockerfile выглядят примерно так:
Решение:
Digest это SHA256 конкретного слоя образа. Он не меняется. Ваш билд от сегодня и билд через полгода используют буквально один и тот же образ.
Получить digest просто:
Как получать обновления безопасности
Тут в игру входят Dependabot и Renovate: они автоматически обновят digest в вашем Dockerfile и откроют PR. Вы видите, что именно изменилось, и сами решаете, мержить или нет.
Добавьте в
Добавьте
После этого обновления приходят сами в виде PR с понятным ченджлогом.
Тег говорит «примерно вот это», digest говорит «именно вот это».
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoDeep
Большинство Dockerfile выглядят примерно так:
FROM golang:1.26.1-alpine
golang:1.26.1-alpine это плавающий тег. Каждый раз, когда upstream обновляет образ: патч безопасности, замена библиотеки, изменение поведения, ваш следующий билд молча подтягивает новую версию. Вы ничего не меняли, а билд сломался.Решение:
# Было
FROM golang:1.26.1-alpine
# Стало
FROM golang:1.26.1-alpine3.20@sha256:a1b2c3d4e5f6...
Digest это SHA256 конкретного слоя образа. Он не меняется. Ваш билд от сегодня и билд через полгода используют буквально один и тот же образ.
Получить digest просто:
docker pull golang:1.26.1-alpine
docker inspect --format='{{index .RepoDigests 0}}' golang:1.26.1-alpine
Как получать обновления безопасности
Тут в игру входят Dependabot и Renovate: они автоматически обновят digest в вашем Dockerfile и откроют PR. Вы видите, что именно изменилось, и сами решаете, мержить или нет.
Добавьте в
.github/dependabot.yml:version: 2
updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
Добавьте
renovate.json в корень репозитория:{
"extends": ["config:base"],
"docker": {
"pinDigests": true
}
}После этого обновления приходят сами в виде PR с понятным ченджлогом.
Тег говорит «примерно вот это», digest говорит «именно вот это».
📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤6
YottaDB это key-value база данных с ACID-транзакциями. YDBGo её официальная Go-обёртка. Вышла вторая версия, посмотрим что поменялось.
Что было не так с v1
v1 имел два API — SimpleAPI и EasyAPI — оба многословные, с неудобными сигнатурами. Каждый вызов требовал передавать
tptoken и errstr, вручную вызывать Alloc и Free, и писать обработку ошибок после каждой операции. Вот как выглядело простое чтение значения:// v1 EasyAPI
x, err := ValE(tptoken, &errstr, varname, subsarray)
if err != nil { ... }
// v2
x := n.Get()
Что изменилось в v2
Центральная идея это доступ к базе через экземпляры
*Conn и *Node. Создаёте соединение, создаёте узел, работаете с ним:db := yottadb.MustInit()
defer yottadb.Shutdown(db)
conn := yottadb.NewConn()
n := conn.Node("varname", "sub1", "sub2")
n.Set("hello")
x := n.Get()
n.Kill()
tptoken и errstr больше нигде не передаются — они хранятся внутри Conn. Буферы освобождаются автоматически через GC — Alloc/Free ушли.Итерация раньше её не было вовсе, нужно было вручную вызывать
SubNextE. Теперь:for node := range n.Children() {
println(node)
}
for node := range n.Tree() {
println(node)
}Транзакции стали лаконичнее:
conn.Transaction("BATCH", nil, func() {
n.Set(value)
})Вызов M-кода из Go:
// v1 — 6 строк с проверками ошибок
// v2
table := conn.MustImport("calltab.ci")
retval := table.Call("mfunc", "param1", 2, 3)
Производительность
v2 быстрее v1 за счёт снижения числа аллокаций.
Node переиспользует буферы при итерации через Index() вместо создания нового объекта на каждый шаг. Конкретные цифры: базовые операции быстрее EasyAPI в 4–7 раз, SimpleAPI — на 1–4%.v1 продолжает поддерживаться, v1 и v2 можно использовать в одном приложении одновременно. Для постепенного перехода — есть таблица соответствия синтаксиса в официальном блоге и диффы реальных миграций.
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍2
❤1
Вышел Neovim 0.12.0. Разбираем главное.
LSP
Добавлено много новых возможностей:
•
textDocument/inlineCompletion — inline-подсказки прямо в редакторе•
textDocument/linkedEditingRange — одновременное редактирование связанных символов, например, открывающий и закрывающий HTML-тег•
textDocument/onTypeFormatting — форматирование во время набора•
textDocument/selectionRange — инкрементальное выделение: v_an расширяет выделение, v_in сужает•
textDocument/documentColor + colorPresentation — предпросмотр цветов прямо в буфере• Переработан
codeLens — теперь отображается как виртуальные строки• Новая команда
:lsp для интерактивного управления LSP-клиентами•
DiagnosticRelatedInformation теперь видна в vim.diagnostic.open_float(), а gf прыгает к проблемному месту•
vim.lsp.buf.rename() подсвечивает переименовываемый символ через hl-LspReferenceTargetНовые команды и плагины
•
:DiffTool — сравнение директорий и файлов•
:Undotree — визуальный навигатор по дереву отмен•
:iput — вставка с автовыравниванием отступа•
:uniq — дедупликация строк в буфере•
:restart — перезапуск Nvim с переподключением текущего UI•
:connect — динамическое подключение UI к серверу•
:wall ++p — автоматически создаёт отсутствующие родительские директории•
gx в help-буферах теперь открывает онлайн-документацию по тегу под курсоромНовые опции
•
autocomplete — включает встроенное автодополнение при наборе•
pumborder — рамка вокруг popup-меню завершения•
winborder — кастомный стиль рамки окна, включая "bold"•
diffop' теперь включает "indent-heuristic" и "inline:char" по умолчанию•
maxsearchcoun' — максимум для searchcount(), по умолчанию 999•
busy — статус «занятости» буфера, отображается в статусной строке символом ◐•
pummaxwidth — максимальная ширина popup-меню завершения•
fillchars получил новый флаг "foldinner"•
listchars получил новый флаг "leadtab"Производительность
•
Ctrl-R для вставки из регистров стал в 10 раз быстрее — теперь работает как paste, а не как ввод пользователя•
vim.glob.to_lpeg() — новая реализация на LPeg, ~50% быстрее для сложных паттернов• LSP semantic tokens теперь запрашиваются только для видимой области экрана (
textDocument/semanticTokens/range) — меньше трафика, быстрее отклик•
:packadd больше не инвалидирует кэш Lua-путей — значительный выигрыш при старте для конфигов с множеством :packadd📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥11🔥9❤2🤔2
Правильный порядок слоёв в Dockerfile решает половину проблемы.
go mod download не перезапускается, если go.mod не менялся, то это знают все. Но стоит обновить любую зависимость, даже патч-версию, и Docker пересобирает слой с нуля: скачивает все модули заново, прогоняет полную компиляцию.BuildKit решает через постоянный кэш, который живёт между билдами независимо от слоёв.
Как это работает:
# syntax=docker/dockerfile:1
FROM golang:1.26.1-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux go build -o /app ./cmd/server
/go/pkg/mod это кэш скачанных модулей. Если пакет уже был загружен в предыдущем билде, он не качается снова даже если слой инвалидирован./root/.cache/go-build это кэш компилятора Go. Файлы, которые не изменились с прошлой сборки, не перекомпилируются. Именно это даёт наибольший выигрыш при инкрементальных изменениях кода.Mount-кэш не попадает в финальный образ. Это не слой, а временная точка монтирования, которая существует только во время RUN. Размер образа не растёт, данные не утекают в прод.
В новых версиях Docker BuildKit включён по умолчанию. Если нет, то включить можно двумя способами:
# Переменная окружения
DOCKER_BUILDKIT=1 docker build .
# Или в /etc/docker/daemon.json
{ "features": { "buildkit": true } }
📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤1
После 15 лет и 847 закрытых issues с пометкой «by design» команда Go приняла proposal #71.
package main
func main() {
x := 42
result := x > 0 ? "positive" : "non-positive"
println(result)
}
Говорят, Роб Пайк плакал, и явно не от радости.
📍 Навигация: Вакансии • Задачи • Собесы
Please open Telegram to view this post
VIEW IN TELEGRAM
😁126😢25👾4🔥2👍1
Представьте: всё работает. Нет алертов, нет красных дашбордов. И вдруг в логах:
request_duration_ms: -43
Проблема в том, что «время» это не одно понятие, а два.
Есть время настенных часов: «который сейчас час?». Оно синхронизируется по сети, корректируется системой и иногда прыгает назад на несколько миллисекунд.
start := time.Now()
// ... передали start в другой сервис, записали в БД ...
elapsed := end.Sub(start) // wall clock — может быть отрицательным
Есть монотонное время: «сколько прошло?». Оно только растёт и не зависит от синхронизации.
start := time.Now()
// ... делаем работу ...
elapsed := time.Since(start) // монотонный компонент, всегда >= 0
Для измерения задержек нужно второе. Но большинство кода использует первое и не замечает разницы, пока не появляется -43ms.
📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥1🤔1
Backend-разработчик (GO) — до 300 000 ₽, удаленно по Москве
Senior Golang Developer — до 280 000 ₽ удаленно по России
Старший разработчик Go (Отдел разработки ядра, отчёты) — от 475 000 ₽, удаленно по МСК
#GoWork
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
✌🏻 У нас две новости — хорошая и плохая!
Хорошая: Ваших знаний, скорее всего, хватит, чтобы собрать рабочую демку AI-агента в Colab. 🫡
Плохая: Вы вряд ли выведете его в прод, не обанкротившись на токенах и не слив базу. 🤯
Для защиты от таких сценариев мы полностью пересобрали курс «Разработка AI-агентов». Теперь внутри плотная работа с экономикой ресурсов, дебаг через time-travel в
Программа курса, полный состав спикеров и другие подробности 👈🏻
ВАЖНО! До 5 апреля на курс действует скидка, но свободные места могут закончиться раньше.
Хорошая: Ваших знаний, скорее всего, хватит, чтобы собрать рабочую демку AI-агента в Colab. 🫡
Плохая: Вы вряд ли выведете его в прод, не обанкротившись на токенах и не слив базу. 🤯
Для защиты от таких сценариев мы полностью пересобрали курс «Разработка AI-агентов». Теперь внутри плотная работа с экономикой ресурсов, дебаг через time-travel в
LangGraph, извлечение данных из кривых сканов для RAG и комплаенс по 152-ФЗ.Если всё ещё сомневаетесь, послушайте голосовое от спикера курса Влада Прошинского, где он объясняет, как правильно тестировать агентов перед релизом.
Программа курса, полный состав спикеров и другие подробности 👈🏻
ВАЖНО! До 5 апреля на курс действует скидка, но свободные места могут закончиться раньше.
🔄 Go 1.26.2 и 1.25.9 выйдут 7 апреля
Команда Go объявила о плановом выпуске двух патч-версий. Релизы состоятся в рабочее время по американскому времени во вторник, 7 апреля.
Оба обновления закрывают уязвимости в стандартной библиотеке и тулчейне. Всего исправлено семь уязвимостей. Детали по каждой уязвимости будут раскрыты только после выхода релизов.
➡️ Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoLive
Команда Go объявила о плановом выпуске двух патч-версий. Релизы состоятся в рабочее время по американскому времени во вторник, 7 апреля.
Оба обновления закрывают уязвимости в стандартной библиотеке и тулчейне. Всего исправлено семь уязвимостей. Детали по каждой уязвимости будут раскрыты только после выхода релизов.
📍 Навигация: Вакансии • Задачи • Собесы
#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Написать свой Language Server с нуля на Go сложно. Нужно разобраться с JSON-RPC фреймингом, маршрутизацией сообщений, типами LSP, управлением жизненным циклом соединения. И всё это до того, как начнёшь писать саму языковую логику.
go-lsp берёт всё это на себя. Библиотека реализует LSP 3.17 и даёт чистый интерфейс, где вы просто описываете, что ваш сервер умеет делать.
go-lsp состоит из трёх пакетов.
jsonrpc отвечает за JSON-RPC 2.0 поверх io.ReadWriteCloser. lsp содержит Go-типы для всех структур протокола, без логики. server связывает всё вместе: принимает хендлер, смотрит какие интерфейсы он реализует и автоматически регистрирует соответствующие LSP-методы.Устанавливаем:
go get github.com/owenrumney/go-lsp
Минимальный сервер с поддержкой hover:
package main
import (
"context"
"os"
"github.com/owenrumney/go-lsp/lsp"
"github.com/owenrumney/go-lsp/server"
)
type Handler struct{}
func (h *Handler) Initialize(ctx context.Context, params *lsp.InitializeParams) (*lsp.InitializeResult, error) {
return &lsp.InitializeResult{
Capabilities: lsp.ServerCapabilities{
HoverProvider: &lsp.HoverOptions{},
},
}, nil
}
func (h *Handler) Shutdown(ctx context.Context) error {
return nil
}
func (h *Handler) Hover(ctx context.Context, params *lsp.HoverParams) (*lsp.Hover, error) {
return &lsp.Hover{
Contents: lsp.MarkupContent{
Kind: lsp.MarkupKindMarkdown,
Value: "Hello from the server",
},
}, nil
}
func main() {
srv := server.NewServer(&Handler{})
if err := srv.Run(context.Background(), server.RunStdio()); err != nil {
os.Exit(1)
}
}
Сервер сам понимает, что хендлер поддерживает hover, потому что он реализует интерфейс HoverHandler. Вручную регистрировать методы не нужно. Хотите добавить completion — реализуйте CompletionHandler.
Обязательный интерфейс только один — LifecycleHandler с методами Initialize и Shutdown. Всё остальное реализуете по мере необходимости.
📍 Навигация: Вакансии • Задачи • Собесы
#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👾1
🛠 Указатели в Go: что нужно понять, чтобы не стрелять себе в ногу
Если вы пришли из JavaScript или Python, указатели поначалу кажутся лишней сложностью. Зачем явно управлять адресами памяти, если язык мог бы сделать это сам? Go даёт вам этот контроль намеренно, и когда понимаешь зачем, код становится предсказуемее.
Что такое указатель
Переменная хранит значение. Указатель хранит адрес памяти, где это значение лежит:
Два оператора, которые нужно запомнить:
Зачем это нужно
В JS объекты всегда передаются по ссылке, примитивы по значению, и вы не выбираете. Go даёт выбор явно для любого типа.
Есть три практических причины использовать указатели.
1. Изменить оригинал внутри функции. Без указателя функция получает копию и работает с ней:
С указателем функция получает адрес и меняет оригинал:
2. Не копировать большую структуру. Когда вы передаёте структуру в функцию по значению, Go копирует её целиком. Для небольших структур это нормально. Для структуры с мегабайтом данных нет:
3. Выразить отсутствие значения. Примитивы в Go не могут быть
Указатель решает это:
Паттерн с хелпером, чтобы не заводить переменную ради указателя:
nil и паника
Нулевое значение указателя это
Правило простое: если указатель пришёл извне (из функции, из структуры, из JSON), проверяйте перед разыменованием. Если вы сами только что создали переменную через
Где указатели не нужны
Слайсы, мапы и каналы уже содержат внутри себя указатель на данные. Передавать
Используйте указатель, когда функции нужно изменить оригинал, когда структура большая, или когда
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoDeep
Если вы пришли из JavaScript или Python, указатели поначалу кажутся лишней сложностью. Зачем явно управлять адресами памяти, если язык мог бы сделать это сам? Go даёт вам этот контроль намеренно, и когда понимаешь зачем, код становится предсказуемее.
Что такое указатель
Переменная хранит значение. Указатель хранит адрес памяти, где это значение лежит:
x := 42
p := &x // p хранит адрес x, например 0xc0000180a0
*p // разыменование: получаем значение по адресу — 42
Два оператора, которые нужно запомнить:
& берёт адрес переменной, * достаёт значение по адресу. Тип *int означает "указатель на int", а не разыменование — контекст определяет смысл.Зачем это нужно
В JS объекты всегда передаются по ссылке, примитивы по значению, и вы не выбираете. Go даёт выбор явно для любого типа.
Есть три практических причины использовать указатели.
1. Изменить оригинал внутри функции. Без указателя функция получает копию и работает с ней:
func double(n int) {
n = n * 2 // меняем копию, оригинал не трогаем
}
x := 5
double(x)
fmt.Println(x) // 5С указателем функция получает адрес и меняет оригинал:
func double(n *int) {
*n = *n * 2
}
x := 5
double(&x)
fmt.Println(x) // 102. Не копировать большую структуру. Когда вы передаёте структуру в функцию по значению, Go копирует её целиком. Для небольших структур это нормально. Для структуры с мегабайтом данных нет:
type Report struct {
Data [1000000]int // ~4MB
}
func process(r Report) { } // копирует 4MB при каждом вызове
func process(r *Report) { } // копирует 8 байт (размер указателя)3. Выразить отсутствие значения. Примитивы в Go не могут быть
nil. Если у вас Age int, нулевое значение это 0, и вы не отличите "возраст не указан" от "возраст ноль".Указатель решает это:
type User struct {
Name string
Age int
Nickname *string // nil = никнейма нет
}
nick := "ali"
user := User{
Name: "Alice",
Age: 30,
Nickname: &nick,
}
if user.Nickname != nil {
fmt.Println(*user.Nickname) // ali
}Паттерн с хелпером, чтобы не заводить переменную ради указателя:
func ptr[T any](v T) *T { return &v }
user.Nickname = ptr("ali")nil и паника
Нулевое значение указателя это
nil. Разыменование nil приводит к панике в рантайме:var p *int
fmt.Println(*p) // panic: invalid memory address or nil pointer dereference
Правило простое: если указатель пришёл извне (из функции, из структуры, из JSON), проверяйте перед разыменованием. Если вы сами только что создали переменную через
&, проверка не нужна — он точно не nil.Где указатели не нужны
Слайсы, мапы и каналы уже содержат внутри себя указатель на данные. Передавать
*[]int или *map[string]int почти никогда не нужно, это добавляет косвенность без выгоды. Небольшие структуры с двумя-тремя полями дешевле копировать, чем ходить по указателю, у процессора меньше работы без дополнительного обращения к памяти.Используйте указатель, когда функции нужно изменить оригинал, когда структура большая, или когда
nil является валидным состоянием. В остальных случаях передавайте значение.📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
❤19👍6
Хранить серию и номер паспорта кажется простой задачей. Но именно разработчики регулярно принимают решение, о котором потом жалеют.
Вариантов много и дискутировать можно бесконечно, но мы подготовили вариант, который удовлетворит 99% кейсов
📍 Навигация: Вакансии • Задачи • Собесы
#ReadySetGo
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2🌚1