我已经设法做到了这一点,但它看起来效率不高:
var t reflect.Type
switch t {
case reflect.TypeOf(([]uint8)(nil)):
// handle []uint8 array 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 := myVar.(type){
case []uint8:
// t is []uint8
case *Foo:
// t is *Foo
default:
panic("unknown type")
}
你到底想完成什么?
最初问题的答案 如何打开反射。类型?是:你不能。但是,您可以使用 reflect.Value
.
- 给定一个变量
v interface{}
你可以调用reflect.TypeOf(v)
和reflect.ValueOf(v)
,它们返回一个reflect.Type
或reflect.Value
。- 如果
v
的类型不是interface{}
则这些函数调用会将其转换为interface{}
。
- 如果
-
reflect.Type
包含有关类型的各种运行时信息,但它不包含任何可用于在类型开关中根据需要检索v
类型本身的信息。 - Hovewer,
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
vs. interface{}
在 Go 中,有两个运行时泛型系统:
- 在语言中:
interface{}
,对于类型开关/断言很有用, - 在库中:
reflect
包,用于检查运行时泛型类型和此类值。
这两个系统是分开的世界,一个系统可能的事情在另一个系统上是不可能的。例如,给定一个interface{}
,在普通 Go(使用安全代码(中,如果值是数组或切片,则无论其元素类型如何,则无法获取第 i 个元素的值。人们需要使用reflect
才能做到这一点。相反,使用reflect
不可能进行类型切换或断言:将其转换为interface{}
,然后您可以这样做。
这些系统之间的接口点很少。在一个方向上,TypeOf()
和 ValueOf()
函数接受interface{}
并返回reflect
结构。在另一个方向上,它是Value.Interface()
.
需要Value
而不是Type
来做类型切换有点违反直觉。至少这与需要通过调用TypeOf()
来构造Type
的值这一事实有些一致。
reflect.Kind
reflect.Type
和reflect.Value
都有Kind()
方法。 有些人建议使用这些方法返回的值(类型为 reflect.Kind
(来模仿类型开关。
虽然这在某些情况下可能很有用,但它不能替代类型开关。例如,使用Kind
无法区分int64
和time.Duration
,因为后者被定义为
type Duration int64
Kind
对于判断类型是否是任何类型的结构、数组、切片等都很有用,无论它由哪种类型组成。这是无法用类型开关找到的。
(旁注。我有同样的问题,发现这里没有答案有帮助,所以我自己去弄清楚。反复的反问"你为什么要这样做?",然后是无关的答案也没有帮助我。我有一个很好的理由,为什么我想这样做。
这可能有效。
switch t := reflect.TypeOf(a).String() {
case "[]uint8":
default:
}
正如其他人所说,目前尚不清楚您通过打开反射来达到什么目的。类型 但是,我在可能尝试做类似的事情时遇到了这个问题,所以如果它回答了您的问题,我会给你我的解决方案。
正如captncraig所说,一个简单的类型切换可以在接口{}变量上完成,而无需使用reflect。
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)
}
}
但是,除此之外,在原始问题的上下文中反射的有用性可能在于接受具有任意类型字段的结构,然后使用类型开关根据其类型处理字段的函数。无需直接打开反射。类型,因为可以通过反射提取类型,然后标准类型开关将起作用。例如:
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)
(关于围棋反思的几点:
- 有必要导出结构字段以便 reflect 能够使用它们,因此字段名称的大写
- 为了修改字段值,必须使用指向结构的指针,如此示例函数所示
- Elem(( 用于在 reflect 中"取消引用"指针
(
好吧,我首先将其传输到接口,然后使用.(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())
}
}