如何启用reflect.Type?

时间:2015-10-30 19:50:25

标签: reflection go

我设法做到了这一点,但看起来效率不高:

var t reflect.Type
switch t {
case reflect.TypeOf(([]uint8)(nil)):
    // handle []uint8 array type
}

6 个答案:

答案 0 :(得分:7)

第一个问题,您确定要打开reflect.Type并且不使用类型开关吗?例如:

switch x := y.(type) {
case []uint8:
  // x is now a []uint8
}

假设这不适用于您的情况,我的建议是制作这些包变量。例如:

var uint8SliceType = reflect.TypeOf(([]uint8)(nil))

func Foo() {
    var t reflect.Type
    switch t {
    case uint8SliceType:
        // handle []uint8 array type
    }

}

答案 1 :(得分:2)

如果您只是想检测类型,则可能不需要反映。

switch t := myVar.(type){
  case []uint8:
    // t is []uint8
  case *Foo:
    // t is *Foo
  default:
    panic("unknown type")
}

你到底想要完成什么?

答案 2 :(得分:2)

最初的问题如何打开reflect.Type?的答案是:你不能。但是,您可以使用 reflect.Value 来实现。

  • 给定变量 v interface{},您可以调用 reflect.TypeOf(v)reflect.ValueOf(v),它们分别返回 reflect.Typereflect.Value
    • 如果 v 的类型不是 interface{},那么这些函数调用会将其转换为 interface{}
  • reflect.Type 包含有关类型的各种运行时信息,但它包含任何可用于在类型切换中根据需要检索 v 本身的类型的信息。
  • 然而,reflect.Value 通过其 Interface() 方法提供它,该方法将底层值作为 interface{} 返回。您可以在类型切换或类型断言中使用它。
import "fmt"
import "reflect"

var v int
var rt reflect.Type = reflect.TypeOf(v)
fmt.Println(rt.String(), " has awesome properties: Its alignment is",
    rt.Align(), ", it has", rt.Size(), "bytes, is it even comparable?",
    rt.Comparable())
// … but reflect.Type won’t tell us what the real type is :(
// Let’s see if reflect.Value can help us.
var rv reflect.Value = reflect.ValueOf(v)
// Here we go:
vi := rv.Interface()
switch vi.(type) {
// Mission accomplished.
}

也许有助于澄清一些可能导致 Go 中动态类型混淆的要点。至少我对此困惑了很长一段时间。

reflect 对比 interface{}

在 Go 中有两个运行时泛型系统:

  • 语言中:interface{},对于类型切换/断言很有用,
  • 中:reflect 包,用于检查运行时泛型类型及其值。

这两个系统是独立的世界,一个可能的事情,另一个不可能。例如,给定一个 interface{},在普通 Go(使用安全代码)中,如果值是数组或切片,无论其元素类型如何,都无法获取第 i 个元素的值元素。需要使用 reflect 才能做到这一点。相反,使用 reflect 是不可能进行类型转换或断言的:将其转换为 interface{},然后您可以这样做。

这些系统之间只有很少的接口点。一方面是 TypeOf()ValueOf() 函数接受 interface{} 并返回 reflect 结构。在另一个方向是 Value.Interface()

需要一个 Value 而不是 Type 来进行类型转换有点违反直觉。至少这与我们需要通过调用 Type 来构造一个 TypeOf() 的事实在某种程度上是一致的。

reflect.Kind

reflect.Typereflect.Value 都有一个 Kind() 方法。一些人建议使用这些方法返回的值(类型为 reflect.Kind)来模拟类型切换。

虽然这在某些情况下可能很有用,但它不能替代类型开关。例如,使用 Kind 无法区分 int64time.Duration,因为后者是 defined as

type Duration int64

Kind 可用于判断类型是否为任何类型的结构、数组、切片等,而不管它由何种类型组成。这是无法通过类型开关找到的。

(旁注。我有同样的问题,但没有找到有用的答案,所以我自己去弄清楚。重复的反问“你为什么要这样做?”,然后是不相关的答案也没有帮助我.我有一个很好的理由为什么我想以这种方式做到这一点。)

答案 3 :(得分:1)

这可能有用。

switch t := reflect.TypeOf(a).String() {
   case "[]uint8":
   default:
}

答案 4 :(得分:0)

正如其他人所说,不清楚您通过打开reflect.Type想要达到什么目的。但是,我在尝试做类似的事情时遇到了这个问题,所以我会给您我的解决方案,以防它回答您的问题。问题。

captncraig said一样,可以在interface {}变量上进行简单的类型切换,而无需使用反射。

func TypeSwitch(val interface{}) {
    switch val.(type) {
        case int:
            fmt.Println("int with value", val)
        case string:
            fmt.Println("string with value ", val)
        case []uint8:
            fmt.Println("Slice of uint8 with value", val)
        default:
            fmt.Println("Unhandled", "with value", val)
    }
}

但是,除此之外,在原始问题上下文中反射的作用可能在于接受具有任意类型字段的结构的函数,然后使用类型开关根据字段的类型对其进行处理。无需直接在reflect.Type上进行切换,因为可以通过reflect提取类型,然后可以使用标准类型开关。例如:

type test struct {
    I int
    S string
    Us []uint8
}

func (t *test) SetIndexedField(index int, value interface{}) {
    e := reflect.ValueOf(t).Elem()
    p := e.Field(index)
    v := p.Interface()
    typeOfF := e.Field(index).Type()
    switch v.(type) {
        case int:
            p.SetInt(int64(value.(int)))
        case string:
            p.SetString(value.(string))
        case []uint8:
            p.SetBytes(value.([]uint8))
        default:
            fmt.Println("Unsupported", typeOfF, v, value)
    }
}

以下示例演示了此功能的用法:

var t = test{10, "test string", []uint8 {1, 2, 3, 4}}
fmt.Println(t)
(&t).SetIndexedField(0, 5)
(&t).SetIndexedField(1, "new string")
(&t).SetIndexedField(2, []uint8 {8, 9})
fmt.Println(t)

(关于go的几点思考:

  1. 必须导出结构字段以使其能够使用反射,因此字段名称必须大写
  2. 为了修改字段值,有必要像本例函数中那样使用指向结构的指针
  3. Elem()用于在反射中“取消引用”指针

答案 5 :(得分:0)

好吧,我首先将其传输到界面,然后使用.(type)

    ty := reflect.TypeOf(*c)
    vl := reflect.ValueOf(*c)
    for i:=0;i<ty.NumField();i++{
        switch vl.Field(i).Interface().(type) {
        case string:
            fmt.Printf("Type: %s Value: %s \n",ty.Field(i).Name,vl.Field(i).String())
        case int:
            fmt.Printf("Type: %s Value: %d \n",ty.Field(i).Name,vl.Field(i).Int())
        }
    }