Для чего нужен type switch в Go
Что проверяют
Понимаете ли вы, как устроен интерфейс в Go: это пара из значения и его динамического типа, и как этот тип безопасно достать. Следом обычно спрашивают про разницу с type assertion, про ловушку с nil и про то, когда type switch лучше заменить методом интерфейса или дженериками.
Как отвечать
Type switch ветвит код по динамическому типу значения в интерфейсе: switch v := x.(type) { case int: ... case string: ... default: ... }. Выражение x обязано быть интерфейсного типа, иначе код не скомпилируется.
- тип
vзависит от ветки: если вcaseодин тип,vимеет этот тип. Если перечислено несколько типов или этоdefault,vостаётся того же типа, чтоx; case nil: срабатывает, когда сам интерфейс пустой, без типа и значения;- порядок важен: ветки проверяются сверху вниз, срабатывает первая подходящая. В
caseможно ставить интерфейсы вродеerrorилиfmt.Stringer, и общий интерфейс выше конкретного типа перехватит всё; fallthroughзапрещён, в отличие от обычногоswitch;- связь с type assertion:
v, ok := x.(T)проверяет один тип, а безokпри несовпадении будет паника. Type switch это удобная запись цепочки таких проверок.
Где применяют: разбор значений any, например после json.Unmarshal в map[string]any, где все числа приходят как float64; обход узлов AST в go/ast; обработка нескольких видов сообщений из одного канала. С дженериками (Go 1.18+) type switch по параметру типа напрямую не работает, значение сначала приводят к any: switch any(v).(type).
Где спотыкаются
Попадают на типизированный nil: var p *MyErr; var err error = p. Здесь err != nil, ветка case nil не сработает, выполнится case *MyErr.
Ждут конкретный тип в ветке с несколькими типами: в case int, int64 выражение v + 1 не скомпилируется, потому что v там интерфейс.
Разбирают ошибки через type switch. Обёрнутую через %w ошибку он не увидит, для этого есть errors.As. А длинный switch по своим типам часто означает, что поведение просится в метод интерфейса.