Что такое type switch?go-43

Type switch — это специальная конструкция в Go, позволяющая определять и обрабатывать разные типы данных в интерфейсной переменной.

Базовый синтаксис

switch v := i.(type) {
case T1:
    // здесь v имеет тип T1
case T2:
    // здесь v имеет тип T2
default:
    // случай, когда тип не соответствует ни одному из case
}

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

  1. Вычисляется выражение i.(type) (только внутри type switch)
  2. Go проверяет фактический тип значения в интерфейсе i
  3. Выполняется ветка case с соответствующим типом
  4. В каждой ветке переменная v имеет конкретный тип из case

Пример с разными типами

func printType(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("Integer: %d\n", v)
    case string:
        fmt.Printf("String: %s\n", v)
    case bool:
        fmt.Printf("Boolean: %v\n", v)
    default:
        fmt.Printf("Unknown type: %T\n", v)
    }
}

Отличия от обычного switch

  1. Используется .(type) вместо значения
  2. Проверяются типы, а не значения
  3. В каждой ветке переменная имеет разный тип

Особенности использования

С пустым интерфейсом

Чаще всего применяется с interface{} для обработки разных типов:

func process(value interface{}) {
    switch v := value.(type) {
    case []byte:
        // обработка []byte
    case string:
        // обработка string
    }
}

С пользовательскими типами

Отлично работает с пользовательскими структурами:

type Dog struct { Name string }
type Cat struct { Name string }

func greet(pet interface{}) {
    switch v := pet.(type) {
    case Dog:
        fmt.Printf("Woof! I'm %s\n", v.Name)
    case Cat:
        fmt.Printf("Meow! I'm %s\n", v.Name)
    }
}

Проверка на nil

Можно обнаружить nil-значение:

switch v := i.(type) {
case nil:
    fmt.Println("nil value")
default:
    fmt.Printf("Type: %T\n", v)
}

Сравнение с type assertion

Type switch — это расширенная версия type assertion:

// Type assertion
if s, ok := i.(string); ok {
    fmt.Println(s)
}

// Эквивалентный type switch
switch s := i.(type) {
case string:
    fmt.Println(s)
}

Производительность

Type switch обычно быстрее серии if-else с type assertions, так как компилятор оптимизирует его как таблицу переходов.

Ограничения

  1. Работает только с интерфейсами
  2. Не поддерживает проверку на несколько типов в одном case (в отличие от обычного switch)
  3. Переменная v в каждом case имеет разную область видимости

Продвинутое использование

Можно использовать для реализации visitor-паттерна:

func visit(node interface{}) {
    switch n := node.(type) {
    case *AstNode:
        visitChildren(n.Children)
    case *LiteralNode:
        processLiteral(n.Value)
    }
}

Резюмируем

  • Type switch — мощный инструмент для работы с интерфейсами
  • Позволяет безопасно проверять и преобразовывать типы
  • Каждая ветка case имеет свою типизированную переменную
  • Альтернатива множественным type assertions
  • Широко применяется при обработке разнотипных данных