Go: Стандартная библиотека

12 вопросов

1 io.Reader и io.Writer в Go. Композиция.

Интерфейсы для чтения и записи байтов: Read(p []byte) (n int, err error), Write(p []byte) (n int, err error). Много типов их реализуют: файлы, сеть, буферы, сжатие. Композиция: io.Copy(dst, src), io.MultiWriter, io.TeeReader, bufio.Reader оборачивает Reader. В Go редко нужны большие иерархии - достаточно маленьких интерфейсов.

n, err := io.Copy(w, r)
buf := bufio.NewReader(r)
line, _ := buf.ReadString('\n')
Открыть отдельно →
2 net/http: сервер и клиент. Основные API.

Сервер: http.Handler (ServeHTTP), http.HandleFunc, http.ListenAndServe. Request - Method, URL, Header, Body. ResponseWriter - WriteHeader, Write, Header(). Клиент: http.Get/Post или http.Client с кастомным Transport и Timeout. Контекст для отмены и таймаута: NewRequestWithContext, клиент передает контекст в запрос. Не забывать закрывать Body ответа.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { ... })
http.ListenAndServe(":8080", nil)
// client
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := client.Do(req)
defer resp.Body.Close()
Открыть отдельно →
3 encoding/json. Теги и обработка ошибок.

Маршалинг и анмаршалинг с тегами json. Ошибки: при Unmarshal неверного типа возвращается ошибка; можно проверить json.UnmarshalTypeError. При неизвестных полях по умолчанию они игнорируются; Decoder.DisallowUnknownFields() запрещает лишние поля. Числа с плавающей точкой по умолчанию - float64; большие целые теряют точность в float - использовать json.Number или string.

dec := json.NewDecoder(r)
dec.DisallowUnknownFields()
var v MyType
if err := dec.Decode(&v); err != nil { ... }
Открыть отдельно →
4 os/exec в Go. Запуск внешних команд.

exec.Command(name, arg...) создает команду; Start/Run/Wait для запуска. Run ждет завершения; Output - запуск и возврат stdout. Контекст для таймаута и отмены: exec.CommandContext(ctx, name, arg...). Важно: не подставлять пользовательский ввод в аргументы без экранирования (безопасность). StdinPipe, StdoutPipe для передачи данных.

cmd := exec.CommandContext(ctx, "git", "clone", url)
cmd.Dir = "/tmp"
out, err := cmd.Output()
Открыть отдельно →
5 path/filepath в Go. Кроссплатформенные пути.

filepath.Join - склейка путей с учетом ОС. filepath.Clean - нормализация. filepath.Walk - обход дерева каталогов. filepath.Abs - абсолютный путь. filepath.Glob - поиск по маске. Для манипуляций URL использовать path (не filepath). В Go предпочтительнее filepath для файловых путей; path - для URL и путей в HTTP.

dir := filepath.Join(home, "config", "app.json")
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { ... })
Открыть отдельно →
6 Пакет time в Go. Таймауты и таймеры.

time.Now(), time.Parse, time.Duration. time.Sleep - блокировка. time.After(d) - канал с сигналом через d (осторожно: таймер не освобождается до срабатывания). time.NewTimer, time.AfterFunc - переиспользуемые. Контекст с таймаутом: context.WithTimeout(ctx, d). Таймзоны: time.LoadLocation, time.FixedZone. Форматирование: time.Format с эталонной датой Mon Jan 2 15:04:05 MST 2006.

ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
t := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
Открыть отдельно →
7 Пакет sync в Go. Mutex, RWMutex, WaitGroup.

sync.Mutex - эксклюзивная блокировка; Lock/Unlock. RWMutex - несколько читателей или один писатель; RLock/RUnlock, Lock/Unlock. sync.WaitGroup - ожидание завершения горутин: Add(n), Done() (равно Add(-1)), Wait(). sync.Once - однократное выполнение. Не копировать мьютексы; разблокировать в defer для избежания паники при ошибке.

var mu sync.RWMutex
mu.RLock()
defer mu.RUnlock()
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); ... }()
wg.Wait()
Открыть отдельно →
8 crypto в Go. Хеши, подписи, TLS.

crypto/sha256, crypto/hmac - хеши и HMAC. crypto/rand - криптостойкая случайность. crypto/rsa, crypto/ecdsa - подписи и шифрование. crypto/tls - TLS. Не использовать crypto/md5 и crypto/sha1 для безопасности; для паролей - bcrypt (golang.org/x/crypto). В Go часто используют стандартные примитивы и x/crypto для доп. алгоритмов.

h := sha256.Sum256(data)
sig, _ := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hashed)
Открыть отдельно →
9 log/slog в Go. Структурированное логирование.

slog (Go 1.21) - структурированные логи: уровни (Debug, Info, Warn, Error), группы (Logger.WithGroup), заменяемый handler (JSON, text). Logger создается с New(slog.NewJSONHandler(...)). Контекст передают через Logger.With. В production обычно JSON handler для парсинга в системах сбора логов.

logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("msg", "user_id", 123, "path", r.URL.Path)
logger.With("request_id", id).Info("request")
Открыть отдельно →
10 embed в Go. Встраивание файлов в бинарник.

Директива //go:embed помещает содержимое файлов в переменную при компиляции. var content []byte с //go:embed file.txt; или embed.FS для каталога. Удобно для шаблонов, статики, конфигов по умолчанию. Ограничения: путь не может содержать .., только файлы в пакете или подкаталогах. В HTTP-сервере можно отдавать встроенные файлы через http.FS.

//go:embed static/*
var staticFS embed.FS
http.Handle("/", http.FileServer(http.FS(staticFS)))
Открыть отдельно →
11 regexp в Go. Компиляция и использование.

regexp.Compile(re) или MustCompile; метод MatchString, FindString, FindAllString, ReplaceAllString. Субматчи: FindStringSubmatch возвращает срезы. Регулярки в Go поддерживают RE2 (без backreferences в полном виде). Для частого использования компилировать один раз и переиспользовать (MustCompile при инициализации).

re := regexp.MustCompile("^(\\w+)@(\\w+\\.\\w+)$")
matches := re.FindStringSubmatch("user@example.com")
// matches[0] - полное совпадение, [1] - первый захват
Открыть отдельно →
12 Пакет context в Go. Отмена и таймауты.

context.Context передает значения, сигнал отмены и дедлайн. context.Background() - корневой. WithCancel, WithTimeout, WithDeadline - производные контексты; при отмене родителя отменяются дочерние. WithValue - ключ и значение (осторожно с типами ключей). В HTTP handler передают r.Context(); при долгих операциях создают контекст с таймаутом. Проверка: ctx.Done(), ctx.Err().

ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
select {
case <-ctx.Done():
    return ctx.Err()
case result := <-ch:
    return result
}
Открыть отдельно →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.