Что означает тип ключевого слова при использовании в коммутаторе?

Я видел несколько примеров этого кода в golang:

func process(node ast.Node) Foo {
    switch n := node.(type) {
        // ... removed for brevity
    }
}

ast.Node - это интерфейс. Является ли код фрагмента node.(type) для отражения; узнать фактических исполнителей интерфейса?

Ответ 1

Да. Он называется переключателем Type. Он позволяет выполнять код в зависимости от фактического типа интерфейса, который вы передаете.

Я думаю, официальная документация, с ее примером, понятна:

Переключатель также может использоваться для обнаружения динамического типа интерфейса переменная. Такой коммутатор типа использует синтаксис утверждения типа с тип ключевого слова внутри круглых скобок. Если переключатель объявляет переменная в выражении, переменная будет иметь соответствующую введите в каждом пункте. Это также идиоматично для повторного использования имени в таких случаев, в действительности объявляющих новую переменную с тем же именем, но различного типа в каждом случае.

var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
case bool:
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

Вы не должны использовать это слишком часто в правильно типизированной программе, но это удобно, когда вам это нужно. Пример использования: предположим, что вы внедряете драйвер базы данных, вам, возможно, придется делать преобразования в зависимости от типа переменных Go. Здесь извлечение драйвера go-sql/mysql:

// Scan implements the Scanner interface.
// The value type must be time.Time or string / []byte (formatted time-string),
// otherwise Scan fails.
func (nt *NullTime) Scan(value interface{}) (err error) {
    if value == nil {
        nt.Time, nt.Valid = time.Time{}, false
        return
    }

    switch v := value.(type) {
    case time.Time:
        nt.Time, nt.Valid = v, true
        return
    case []byte:
        nt.Time, err = parseDateTime(string(v), time.UTC)
        nt.Valid = (err == nil)
        return
    case string:
        nt.Time, err = parseDateTime(v, time.UTC)
        nt.Valid = (err == nil)
        return
    }

    nt.Valid = false
    return fmt.Errorf("Can't convert %T to time.Time", value)
}

Ответ 2

Это TYPE SWITCH:

Переключатель также может использоваться для обнаружения динамического типа интерфейса переменная. Такой коммутатор типа использует синтаксис утверждения типа с тип ключевого слова внутри круглых скобок. Если переключатель объявляет переменная в выражении, переменная будет иметь соответствующую введите в каждом пункте. Это также идиоматично для повторного использования имени в таких случаев, в действительности объявляющих новую переменную с тем же именем, но различного типа в каждом случае.

С помощью переключателя типа вы можете включить тип значения интерфейса (только):

func do(v interface{}) string {
        switch u := v.(type) {
        case int:
                return strconv.Itoa(u*2) // u has type int
        case string:
                mid := len(u) / 2 // split - u has type string
                return u[mid:] + u[:mid] // join
        }
        return "unknown"
}

do(21) == "42"
do("bitrab") == "rabbit"
do(3.142) == "unknown"