英文:
How to switch on reflect.Type?
问题
我已经成功完成了这个任务,但是它看起来并不高效:
var t reflect.Type
switch t {
case reflect.TypeOf(([]uint8)(nil)):
    // 处理 []uint8 数组类型
}
英文:
I have managed to do this, but it does not look efficient:
var t reflect.Type
switch t {
case reflect.TypeOf(([]uint8)(nil)):
	// handle []uint8 array type
}
答案1
得分: 10
首先的问题,你确定要使用 reflect.Type 而不是使用类型切换(type switch)吗?例如:
switch x := y.(type) {
case []uint8:
  // x 现在是一个 []uint8
}
假设这种方法对你的情况不适用,我建议将这些变量定义为包级变量。例如:
var uint8SliceType = reflect.TypeOf(([]uint8)(nil))
func Foo() {
    var t reflect.Type
    switch t {
    case uint8SliceType:
        // 处理 []uint8 数组类型
    }
}
英文:
First question, are you sure you want to switch on reflect.Type and not use a type switch? Example:
switch x := y.(type) {
case []uint8:
  // x is now a []uint8
}
Assuming that will not work for your situation, my recommendation is to make those package variables. Example:
var uint8SliceType = reflect.TypeOf(([]uint8)(nil))
func Foo() {
    var t reflect.Type
    switch t {
    case uint8SliceType:
        // handle []uint8 array type
    }
}
答案2
得分: 8
如果你只是想检测类型,可能不需要使用 reflect。
switch t := myVar.(type) {
  case []uint8:
    // t 是 []uint8 类型
  case *Foo:
    // t 是 *Foo 类型
  default:
    panic("未知类型")
}
你实际上想要实现什么?
英文:
you may not need reflect if you are just trying to detect type.
switch t := myVar.(type){
  case []uint8:
    // t is []uint8
  case *Foo:
    // t is *Foo
  default:
    panic("unknown type")
}
What are you actually trying to accomplish?
答案3
得分: 6
初始问题“如何打开reflect.Type?”的答案是:你不能。然而,你可以使用reflect.Value来实现。
- 给定一个变量
v interface{},你可以调用reflect.TypeOf(v)和reflect.ValueOf(v),分别返回reflect.Type或reflect.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{},然后才能进行操作。
这两个系统之间只有非常少的接口。在一方面,是接受interface{}并返回reflect结构的TypeOf()和ValueOf()函数。在另一方面,是Value.Interface()方法。
有点违反直觉的是,进行类型切换需要一个Value而不是一个Type。至少这在某种程度上与通过调用TypeOf()需要一个值来构造一个Type是一致的。
reflect.Kind
reflect.Type和reflect.Value都有一个Kind()方法。有人建议使用这些方法返回的reflect.Kind类型的值来模拟类型切换。
虽然在某些情况下这可能有用,但它不能替代类型切换。例如,使用Kind无法区分int64和time.Duration,因为后者被定义为:
type Duration int64
Kind可以告诉我们一个类型是否是任何类型的结构体、数组、切片等,而不考虑它所组成的类型。这是无法通过类型切换找出的。
(顺便说一句,我也有同样的问题,并没有在这里找到有用的答案,所以我自己去弄清楚了。反复问“你为什么要这样做?”然后得到无关的答案并没有帮助我。我有一个很好的理由,为什么我想要以这种方式做。)
英文:
The answer to the initial question How to switch on reflect.Type? is: You can’t. However, you can do it with reflect.Value.
- Given a variable 
v interface{}you can callreflect.TypeOf(v)andreflect.ValueOf(v), which return areflect.Typeorreflect.Value, resp.- If the type of 
vis notinterface{}then these function calls will convert it tointerface{}. 
 - If the type of 
 reflect.Typecontains various run-time information about the type, but it does not contain anything usable to retrieve the type ofvitself as needed in a type switch.- Hovewer, 
reflect.Valueprovides it through itsInterface()method, which returns the underlying value asinterface{}. This you can use in a type switch or type assertion. 
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.
}
Perhaps it helps to clarify a few points which may cause confusion about dynamic typing in Go. At least I was confused by this for quite some time.
reflect vs. interface{}
In Go there are two systems of run-time generics:
- In the language: 
interface{}, useful for type switches/assertions, - In the library: The 
reflectpackage, useful for inspection of run-time generic types and values of such. 
These two systems are separated worlds, and things that are possible with one are impossible with the other. For example, Given an interface{}, it is in plain Go (with safe code) impossible to, say, if the value is an array or slice, regardless of its element type, then get the value of the i-th element. One needs to use reflect in order to do that. Conversely, with reflect it is impossible to make a type switch or assertion: convert it to interface{}, then you can do that.
There are only very few points of an interface between these systems. In one direction it is the TypeOf() and ValueOf() functions which accept interface{} and return a reflect struct. In the other direction it is Value.Interface().
It is a bit counter-intuitive that one needs a Value, not a Type, to do a type switch. At least this is somewhat consistent with the fact that one needs a value construct a Type by calling TypeOf().
reflect.Kind
Both reflect.Type and reflect.Value have a Kind() method.  Some suggest using the value these methods return, of type reflect.Kind, to imitate a type switch.
While this may be useful in certain situations, it is not a replacement for a type switch. For example, using Kind one cannot distinguish between int64 and time.Duration because the latter is defined as
type Duration int64
Kind is useful to tell if a type is any kind of struct, array, slice etc., regardless of the types it is composed of. This is not possible to find out with a type switch.
(Side note. I had the same question and found no answer here helpful so I went to figure it out myself. The repeated counter-question “why are you doing this?”, followed by unrelated answers did not help me either. I have a good reason why I want to do it precisely this way.)
答案4
得分: 1
这可能有效。
switch t := reflect.TypeOf(a).String() {
   case "[]uint8":
   default:
}
英文:
This might work.
switch t := reflect.TypeOf(a).String() {
   case "[]uint8":
   default:
}
答案5
得分: 0
正如其他人所说,你通过打开 reflect.Type 来实现什么目标并不清楚。然而,我在尝试做类似事情时遇到了这个问题,所以我将给出我的解决方案,以防它能回答你的问题。
正如 captncraig 所说,可以在 interface{} 变量上进行简单的类型切换,而不需要使用 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)
    }
}
然而,超越这一点,在原始问题的上下文中,反射的有用性可能在于接受一个具有任意类型字段的结构体的函数,然后使用类型切换根据其类型处理字段。不需要直接在 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 中的反射的一些要点:
- 必须导出结构体字段,以便 reflect 能够使用它们,因此字段名首字母大写。
 - 为了修改字段的值,需要像这个示例函数中一样使用结构体的指针。
 - 使用 Elem() 来“解引用”反射中的指针。
 
英文:
As others have said, it's not clear what you are trying to achieve by switching on reflect.Type However, I came across this question when probably trying to do something similar, so I will give you my solution in case it answers your question.
As captncraig said, a simple type switch could be done on a interface{} variable without needing to use 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)
    }
}
However, going beyond this, the usefulness of reflection in the context of the original question could be in a function that accepts a struct with arbitrarily typed fields, and then uses a type switch to process the field according to its type. It is not necessary to switch directly on reflect.Type, as the type can be extracted by reflect and then a standard type switch will work. For example:
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)
    }
}
The following examples demonstrate the use of this function:
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)
(A few points on reflection in go:
- It is necessary to export the struct fields for reflect to be able to use them, hence the capitalisation of the field names
 - In order to modify the field values, it would be necessary to use a pointer to the struct as in this example function
 - Elem() is used to "dereference" the pointer in reflect
 
)
答案6
得分: 0
好的,以下是翻译好的内容:
	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("类型: %s 值: %s \n", ty.Field(i).Name, vl.Field(i).String())
		case int:
			fmt.Printf("类型: %s 值: %d \n", ty.Field(i).Name, vl.Field(i).Int())
		}
	}
英文:
Well, I did this by first transfer it to interface and then use the.(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())
		}
	}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论