2016-08-03 2 views
4

Как использовать переключатель типа Go в соответствии с общим срезом, массивом, картой или каналом?Переключатель типа Golang: как совместить общий срез/массив/карту/chan?

package main 

import (
    "fmt" 
    "reflect" 
) 

func WhatIsIt(x interface{}) { 
    switch X := x.(type) { 
     case bool: 
      fmt.Printf("Type Switch says %#v is a boolean.\n", X) 
     case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 
      fmt.Printf("Type Switch says %#v is an integer.\n", X) 
     case float32, float64, complex64, complex128: 
      fmt.Printf("Type Switch says %#v is a floating-point.\n", X) 
     case string: 
      fmt.Printf("Type Switch says %#v is a string.\n", X) 
     case []interface{}: 
      fmt.Printf("TypeSwitch says %#v is a slice.\n", X) 
     case map[interface{}]interface{}: 
      fmt.Printf("TypeSwitch says %#v is a map.\n", X) 
     case chan interface{}: 
      fmt.Printf("TypeSwitch says %#v is a channel.\n", X) 
     default: 
      switch reflect.TypeOf(x).Kind() { 
       case reflect.Slice, reflect.Array, reflect.Map, reflect.Chan: 
        fmt.Printf("TypeSwitch was unable to identify this item. Reflect says %#v is a slice, array, map, or channel.\n", X) 
       default: 
        fmt.Printf("Type handler not implemented: %#v\n", X) 
      } 
    } 
} 

func main() { 
    WhatIsIt(true) 
    WhatIsIt(1) 
    WhatIsIt(1.5) 
    WhatIsIt("abc") 
    WhatIsIt([]int{1,2,3}) 
    WhatIsIt(map[int]int{1:1, 2:2, 3:3}) 
    WhatIsIt(make(chan int)) 
} 

Вот результат:

Type Switch says true is a boolean. 
Type Switch says 1 is an integer. 
Type Switch says 1.5 is a floating-point. 
Type Switch says "abc" is a string. 
TypeSwitch was unable to identify this item. Reflect says []int{1, 2, 3} is a slice, array, map, or channel. 
TypeSwitch was unable to identify this item. Reflect says map[int]int{1:1, 2:2, 3:3} is a slice, array, map, or channel. 
TypeSwitch was unable to identify this item. Reflect says (chan int)(0x104320c0) is a slice, array, map, or channel. 

Как видно из вывода, то case []interface{} не совпадает ломоть, что я отправляю в мне нужно прибегать к использованию reflect пакета вместо этого..

Если я явно пишу case []int, то он работает для моего приведенного примера, но невозможно заранее знать все типы ввода, поэтому мне нужно более общее решение. Я хочу, чтобы избежать использования пакета reflect, если коммутатор Type способен справиться с этим.

Можно ли использовать переключатель типа, чтобы определить, является ли объект срезом/массивом/картой/chan/etc ...?

ответ

11

Коммутаторы типа работают с определенными типами. Если вы не можете перечислить все типы в коммутаторе, то единственным вариантом является использование пакета отражения.

v := reflect.ValueOf(x) 
switch v.Kind() { 
case reflect.Bool: 
    fmt.Printf("bool: %v\n", v.Bool()) 
case reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64: 
    fmt.Printf("int: %v\n", v.Int()) 
case reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint64: 
    fmt.Printf("int: %v\n", v.Uint()) 
case reflect.Float32, reflect.Float64: 
    fmt.Printf("float: %v\n", v.Float()) 
case reflect.String: 
    fmt.Printf("string: %v\n", v.String()) 
case reflect.Slice: 
    fmt.Printf("slice: len=%d, %v\n", v.Len(), v.Interface()) 
case reflect.Map: 
    fmt.Printf("map: %v\n", v.Interface()) 
case reflect.Chan: 
    fmt.Printf("chan %v\n", v.Interface()) 
default: 
    fmt.Println(x) 
}