Go 1.27: 50 готовых программ на Golang с примерами кода и лучшими практиками

Изучаете Go (Golang) или ищете готовые примеры для реального проекта? В этой подборке собраны практические программы на Go 1.27: от работы со строками, файлами и JSON до HTTP API, goroutines, каналов, generics и конкурентного программирования.
Все примеры можно скопировать, запустить и адаптировать под свой проект.
Что будет в подборке
1. Hello World на Go
2. Работа со строками
3. Массивы и slices
4. Maps
5. Struct и методы
6. Интерфейсы
7. Обработка ошибок
8. Чтение и запись файлов
9. JSON encode/decode
10. HTTP GET-запрос
11. REST API на `net/http`
12. Middleware
13. Context и timeout
14. Goroutines
15. Channels
16. Worker Pool
17. Mutex и атомики
18. Generics
19. Generic methods в Go 1.27
20. Iterator
21. Работа с PostgreSQL
22. Транзакции SQL
23. Graceful Shutdown
24. Retry с exponential backoff
25. Rate Limiter
26. Кэш с TTL
27. Pipeline
28. Fan-in / Fan-out
29. Unit-тесты
30. Benchmark
Пример: простой HTTP API на Go 1.27
package main
import (
"encoding/json"
"log"
"net/http"
)
type Response struct {
Message string `json:"message"`
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /api/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(Response{
Message: "Hello from Go 1.27",
})
})
log.Println("Server started on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}Пример: Worker Pool на Go
package main
import (
"fmt"
"sync"
)
func worker(jobs <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
fmt.Println("processing:", job)
}
}
func main() {
jobs := make(chan int)
var wg sync.WaitGroup
for range 3 {
wg.Add(1)
go worker(jobs, &wg)
}
for i := range 10 {
jobs <- i
}
close(jobs)
wg.Wait()
}Лучшие практики Go
- всегда проверяйте
error; - передавайте
context.Contextдля операций ввода-вывода; - не запускайте goroutine без понятного способа её остановить;
- используйте
deferдля освобождения ресурсов; - предпочитайте маленькие интерфейсы;
- форматируйте проект через
gofmt; - запускайте
go vetи тесты перед сборкой; - проверяйте конкурентный код через
go test -race; - не добавляйте зависимости, если задачу нормально решает стандартная библиотека.
Что нового в Go 1.27
Одно из главных изменений Go 1.27 — generic methods: теперь методы могут объявлять собственные type parameters.
type Box struct{}
func (Box) Convert[T ~int | ~int64](value T) T {
return value
}Это позволяет использовать generics в API типов значительно естественнее.
Все примеры рассчитаны на современный Go 1.27 и подходят для обучения, собеседований и реальных backend-проектов.
## 31. Structured Logging через slog
```go
package main
import (
"log/slog"
"os"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info(
"user logged in",
"user_id", 42,
"role", "admin",
)
}Для production лучше использовать структурированные логи вместо fmt.Println.
32. HTTP Middleware
func logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}Подключение:
mux := http.NewServeMux()
mux.HandleFunc("GET /", handler)
http.ListenAndServe(":8080", logging(mux))33. HTTP-запрос с timeout
ctx, cancel := context.WithTimeout(
context.Background(),
3*time.Second,
)
defer cancel()
req, err := http.NewRequestWithContext(
ctx,
http.MethodGet,
"https://example.com",
nil,
)
if err != nil {
log.Fatal(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()Не делайте сетевые запросы без timeout.
34. Graceful Shutdown HTTP-сервера
server := &http.Server{
Addr: ":8080",
Handler: mux,
}
ctx, stop := signal.NotifyContext(
context.Background(),
os.Interrupt,
syscall.SIGTERM,
)
defer stop()
go func() {
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}()
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(
context.Background(),
5*time.Second,
)
defer cancel()
server.Shutdown(shutdownCtx)Так сервер успеет завершить активные запросы перед остановкой.
35. Ограничиваем количество goroutines
sem := make(chan struct{}, 5)
var wg sync.WaitGroup
for i := range 100 {
wg.Add(1)
go func(id int) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
fmt.Println("job:", id)
}(i)
}
wg.Wait()Вместо запуска тысяч тяжёлых задач одновременно ограничиваем concurrency.
36. Выполнить функцию только один раз
loadConfig := sync.OnceValue(func() string {
fmt.Println("loading...")
return "production"
})
fmt.Println(loadConfig())
fmt.Println(loadConfig())Функция выполнится один раз, результат будет закэширован.
37. Безопасный счётчик через atomic
var counter atomic.Int64
var wg sync.WaitGroup
for range 1000 {
wg.Add(1)
go func() {
defer wg.Done()
counter.Add(1)
}()
}
wg.Wait()
fmt.Println(counter.Load())Для простых счётчиков atomic часто удобнее Mutex.
38. Правильная работа с errors.Is
var ErrNotFound = errors.New("not found")
func findUser() error {
return fmt.Errorf("find user: %w", ErrNotFound)
}
func main() {
err := findUser()
if errors.Is(err, ErrNotFound) {
fmt.Println("user not found")
}
}Не сравнивайте wrapped errors через обычный ==.
39. errors.As для собственных ошибок
type ValidationError struct {
Field string
}
func (e *ValidationError) Error() string {
return "invalid field: " + e.Field
}
func main() {
err := error(&ValidationError{Field: "email"})
var target *ValidationError
if errors.As(err, &target) {
fmt.Println(target.Field)
}
}40. Потоковое чтение большого JSON
decoder := json.NewDecoder(os.Stdin)
for decoder.More() {
var item struct {
ID int `json:"id"`
Name string `json:"name"`
}
if err := decoder.Decode(&item); err != nil {
log.Fatal(err)
}
fmt.Println(item)
}Для больших данных лучше использовать streaming, а не загружать всё в память.
41. Context отменяет всю цепочку задач
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(time.Second)
cancel()
}()
select {
case <-time.After(5 * time.Second):
fmt.Println("finished")
case <-ctx.Done():
fmt.Println("cancelled")
}context.Context должен передавать отмену через всю цепочку операций.
42. Generic Methods в Go 1.27
Go 1.27 добавил generic methods.
type Converter struct{}
func (Converter) Convert[T ~int | ~int64](v T) T {
return v
}
func main() {
c := Converter{}
fmt.Println(c.Convert(42))
fmt.Println(c.Convert(int64(100)))
}Теперь type parameters можно объявлять непосредственно у метода.
43. Собственный iterator
func Numbers(n int) iter.Seq[int] {
return func(yield func(int) bool) {
for i := range n {
if !yield(i) {
return
}
}
}
}
func main() {
for n := range Numbers(5) {
fmt.Println(n)
}
}Результат:
0
1
2
3
444. Сортировка структур через slices.SortFunc
users := []User{
{Name: "Bob", Age: 31},
{Name: "Alice", Age: 24},
}
slices.SortFunc(users, func(a, b User) int {
return cmp.Compare(a.Age, b.Age)
})Не обязательно писать собственную реализацию сортировки.
45. Retry с exponential backoff
func retry(ctx context.Context, fn func() error) error {
delay := 100 * time.Millisecond
for attempt := range 5 {
if err := fn(); err == nil {
return nil
}
if attempt == 4 {
break
}
select {
case <-time.After(delay):
delay *= 2
case <-ctx.Done():
return ctx.Err()
}
}
return errors.New("all attempts failed")
}Retry должен иметь лимит попыток, backoff и возможность отмены через context.
46. Worker Pool с результатами
func worker(
jobs <-chan int,
results chan<- int,
) {
for n := range jobs {
results <- n * n
}
}Worker Pool полезен, когда нужно контролировать количество одновременно выполняемых задач.
47. Безопасная запись файла
tmp := "config.json.tmp"
if err := os.WriteFile(tmp, data, 0644); err != nil {
log.Fatal(err)
}
if err := os.Rename(tmp, "config.json"); err != nil {
log.Fatal(err)
}Сначала записываем временный файл, затем заменяем основной.
48. Проверка нескольких условий через switch
switch {
case age < 18:
fmt.Println("minor")
case age < 65:
fmt.Println("adult")
default:
fmt.Println("senior")
}В Go switch без выражения часто читается лучше длинной цепочки if/else.
49. Безопасное преобразование типа
value := any("hello")
text, ok := value.(string)
if !ok {
fmt.Println("not a string")
return
}
fmt.Println(text)Не используйте type assertion без ok, если тип значения заранее неизвестен.
50. Проверка программы на race condition
Запуск:
go test -race ./...Race Detector помогает находить ситуации, когда несколько goroutines одновременно небезопасно обращаются к общей памяти.
Для concurrent Go-кода это одна из самых полезных проверок перед production.
Лучшие практики Go 1.27
- используйте
context.Contextдля timeout и cancellation; - ограничивайте количество goroutines;
- оборачивайте ошибки через
%w; - проверяйте ошибки через
errors.Isиerrors.As; - используйте
log/slogдля структурированных логов; - ставьте timeout на HTTP-клиенты и серверы;
- реализуйте graceful shutdown;
- используйте стандартную библиотеку, когда сторонняя зависимость не нужна;
- регулярно запускайте
go test ./...; - для concurrent-кода запускайте
go test -race ./...; - форматируйте код через
gofmt.
Что изучать дальше
После базового Go переходите к:
HTTP → PostgreSQL → concurrency → context → testing → profiling → observability → distributed systems.
Именно эти темы чаще всего встречаются в реальных backend-проектах на Golang.






