Type assertion и switch

Тема дорожной карты · Golang

Утверждения типов и type switch в Go — механизмы для проверки и извлечения конкретного типа, хранящегося внутри интерфейсного значения, обеспечивающие динамическую диспетчеризацию в Golang-программах без рефлексии. Утверждение типа v, ok := i.(ConcreteType) безопасно извлекает базовое значение: если ok равно false, конкретный тип не совпадает, тогда как однозначная форма v := i.(ConcreteType) паникует при несоответствии и используется только когда тип гарантирован. Type switch расширяет одно утверждение на несколько альтернатив: switch v := i.(type) { case *http.Request: ... case io.Reader: ... } позволяет Golang-коду ветвиться по рантайм-типу интерфейсного значения, что распространено в middleware, сериализаторах и коде обработки ошибок. Утверждения типов и type switch активно используются с интерфейсом error: var pgErr *pgconn.PgError; errors.As(err, &pgErr) — идиоматичная форма Go 1.13+, обходящая цепочки ошибок и заменяющая сырые утверждения типов при проверке ошибок pgx, sqlx и gRPC. Понимание утверждений типов и type switch углубляет понимание того, как Go-интерфейсы работают во время выполнения, — что необходимо для написания корректных middleware, кастомных маршалеров encoding/json и извлечения атрибутов спанов OpenTelemetry.

Как это работает

Type assertion и switch покрывает встроенное: массивы (фиксированный размер — редко в идиоматичном Go), slices (динамические массивы — рабочая лошадка), maps (map[K]V, на хешах), strings (UTF-8 байтовые последовательности, неизменяемые). Struct — пользовательские типы с именованными полями; методы на типах (func (r Receiver) Method()); интерфейсы декларируют наборы методов (удовлетворяются неявно — нет ключевого слова implements). Указатели через & и *; slices и maps уже содержат указатели внутри.

Когда применять

Slices везде, где массивы соблазняют — почти всегда правильный ответ. Map — для lookup по ключу; помните, что Go-map не упорядочены. Embedding struct — для композиции (нет эквивалента наследования). Маленькие интерфейсы (1-3 метода) — Go-интерфейсы лучше когда обнаружены, чем объявлены (выносите, когда есть 2+ реализаций).

Типичные ошибки

Ловушки Type assertion и switch: slice-граблик — append(s, x) может или не может делить underlying массив с s (при реалокации не делит — тихие баги); for _, v := range slice { go func() { use(v) }() } захватывает v по ссылке до 1.22 (closures видят последнее значение — починено в 1.22, но многие туториалы до этого); nil-maps паникуют на запись (make(map[K]V)); огромные interface-типы убивают идиому "implicitly satisfied".

Связанные понятия

Полезные ресурсы