如何开启reflect.Type?

How to switch on reflect.Type?

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

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

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

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

您实际上想要完成什么?

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

}

这可能有效。

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

正如其他人所说,不清楚你想通过打开 reflect.Type 来实现什么,但是,我在可能尝试做类似的事情时遇到了这个问题,所以我会在如果它回答了你的问题。

一样,可以在接口{}变量上完成简单的类型切换,而无需使用反射。

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
  4. 中“取消引用”指针

)

第一个问题 如何开启 reflect.Type? 的答案是:你不能。但是,您可以使用 reflect.Value.

  • 给定一个变量 v interface{},您可以分别调用 reflect.TypeOf(v)reflect.ValueOf(v),其中 return 为 reflect.Typereflect.Value
    • 如果 v 的类型不是 interface{} 那么这些函数调用会将其转换为 interface{}
  • reflect.Type 包含有关该类型的各种 运行 时间信息,但它 包含任何可用于检索 [=18= 类型的信息] 本身根据需要在类型开关中。
  • 然而,reflect.Value 通过其 Interface() 方法提供它,return 的基础值是 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{},对switches/assertions、
  • 类型有用
  • 库中 reflect 包,用于检查 运行-time 泛型类型和此类值。

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

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

需要 Value 而不是 Type 来进行类型转换有点违反直觉。至少这与需要一个值通过调用 TypeOf().

构造一个 Type 这一事实有些一致。

reflect.Kind

reflect.Typereflect.Value 都有一个 Kind() 方法。有些人建议使用 reflect.Kind 类型的这些方法 return 的值来模仿类型开关。

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

type Duration int64

Kind 有助于判断一个类型是否是任何类型的结构、数组、切片等,而不管它由什么类型组成。这是不可能用类型开关找出来的。

(旁注。我有同样的问题,但在这里找不到有用的答案,所以我自己去弄明白了。反复反问“你为什么这样做?”,然后是不相关的答案没有帮助我也是。我有一个很好的理由来精确地这个方式。)

好吧,我是通过先将其传输到界面然后使用 .(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())
        }
    }