【问题标题】:How to switch on reflect.Type?如何打开reflect.Type?
【发布时间】:2016-01-31 08:15:30
【问题描述】:

我已经设法做到了,但看起来效率不高:

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

【问题讨论】:

    标签: reflection go


    【解决方案1】:

    第一个问题,您确定要打开 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
        }
    
    }
    

    【讨论】:

    • 最好使用const。编辑:没关系,你必须使用var
    【解决方案2】:

    如果你只是想检测类型,你可能不需要反射。

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

    你真正想要完成什么?

    【讨论】:

      【解决方案3】:

      第一个问题如何开启 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 中的动态类型产生混淆的点。至少我为此困惑了很长时间。

      reflectinterface{}

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

      • 语言中:interface{},对于类型开关/断言很有用,
      • 库中reflect 包,用于检查运行时泛型类型和此类值。

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

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

      需要Value 而不是Type 来进行类型切换有点违反直觉。至少这与以下事实有些一致,即需要通过调用TypeOf() 来构造Type 的值。

      reflect.Kind

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

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

      type Duration int64
      

      Kind 有助于判断一个类型是否是任何类型的结构、数组、切片等,无论它由什么类型组成。这是无法通过类型开关找到的。

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

      【讨论】:

        【解决方案4】:

        这可能有效。

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

        【讨论】:

          【解决方案5】:

          正如其他人所说,目前尚不清楚您通过打开 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,因为可以通过反射提取类型,然后使用标准类型开关。例如:

          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() 用于“取消引用”reflect 中的指针

          )

          【讨论】:

            【解决方案6】:

            好吧,我这样做是先将其传输到接口,然后使用.(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())
                    }
                }
            

            【讨论】:

              猜你喜欢
              • 2011-10-31
              • 1970-01-01
              • 1970-01-01
              • 2019-05-23
              • 2011-04-03
              • 2015-07-10
              • 2018-12-24
              • 2015-08-21
              • 2018-10-02
              相关资源
              最近更新 更多