英文:
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.Type
orreflect.Value
, resp.- If the type of
v
is notinterface{}
then these function calls will convert it tointerface{}
.
- If the type of
reflect.Type
contains various run-time information about the type, but it does not contain anything usable to retrieve the type ofv
itself as needed in a type switch.- Hovewer,
reflect.Value
provides 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
reflect
package, 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())
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论