如何使用 reflect 包来检查结构体字段的类型是否为 interface{}?

huangapple go评论81阅读模式
英文:

How do I use reflect to check if the type of a struct field is interface{}?

问题

我正在使用reflect包来确定一个结构体字段的类型是否为interface{}

我想要进行如下的比较(其中t是一个reflect.Type):

if t == reflect.TypeOf(interface{}) {

}

问题是编译器报错:type interface {} is not an expression

有没有办法检查结构体字段的类型是否为interface{}

英文:

I am using the reflect package to determine the type of a struct field is interface{}

I want to do the comparison like so (where t is a reflect.Type):

if  t == reflect.TypeOf(interface{}) {

}

The problem is that the compiler complains: type interface {} is not an expression.

Is there anyway to check if the type of a struct field is an interface{}?

答案1

得分: 7

你可以通过创建一个空实例并使用反射来获取接口Y的类型:

yType := reflect.TypeOf((*Y)(nil)).Elem()

然后使用表达式

reflect.TypeOf(x).Implements(yType)

来检查类型是否实现了该接口。

接口本身不能被实例化。空接口interface{}被所有类型实现,因此所有字段都实现了它。

实际上,你也可以使用空接口interface{}本身,但这将始终返回true(如果我没有漏掉什么的话):

https://play.golang.org/p/29rWP4LtIo

英文:

You can get the type of the interface Y by creating a nil instance and using reflection:

yType := reflect.TypeOf((*Y)(nil)).Elem()

and then use the expression

reflect.TypeOf(x).Implements(yType)

to check if the type implements the interface.

Interfaces themselves can not be instantiated. The interface{} interface which is the empty interface is implemented by all types so all fields implement that.

https://play.golang.org/p/gRfheIW_9Y

Actually it also works with the empty interface{} itself but this will always return true (if i'm not missing something):

https://play.golang.org/p/29rWP4LtIo

答案2

得分: 5

interface{}是一种类型,而reflect.TypeOf()期望一个值作为参数。所以你不能直接将字面量interface{}传递给它。你只能传递一个值。

回到原始问题。我们来看一个struct的例子:

type My struct {
    A int
    B interface{}
    C io.Reader
}

你想要判断一个字段的类型是否为interface{}。首先获取struct类型的reflect.Type,然后可以使用Type.Field()Type.FieldByName()来访问字段。

这将给你一个类型为reflect.StructField的值,它存储了字段的类型。

到目前为止都很好。但是我们应该与什么进行比较呢?interface{}是一个没有方法的接口类型。你不能拥有(实例化)该类型的值。你只能拥有具体类型的值,但是是可以包装在接口类型中的。

你可以使用Type.Kind,并将其与reflect.Interface进行比较,这可以告诉你它是否是一个接口类型,但是对于所有接口类型都返回true。你还可以使用Type.NumMethod()来检查它是否有0个方法,对于interface{}来说必须为0,但是其他接口类型也可能有0个方法……

你可以使用Type.Name,但是由于interface{}是一个_无名_类型,它的名称是空字符串""(还有其他无名类型)。你可以使用Type.String(),它对于空接口返回"interface {}"

t := reflect.TypeOf(My{})

for i := 0; i < t.NumField(); i++ {
    f := t.Field(i)
    fmt.Printf("Field %q, type: %-12v, type name: %-8q, is interface{}: %v\n",
        f.Name, f.Type,
        f.Type.Name(),
        f.Type.String() == "interface {}",
    )
}

输出结果(在Go Playground上尝试):

Field "A", type: int         , type name: "int"   , is interface{}: false
Field "B", type: interface {}, type name: ""      , is interface{}: true
Field "C", type: io.Reader   , type name: "Reader", is interface{}: false

你可能会发现这个相关问题有趣/有用:https://stackoverflow.com/questions/36310538/identify-non-builtin-types-using-reflect/37292523#37292523

英文:

interface{} is a type, and reflect.TypeOf() expects a value. So you can't pass the literal interface{} to it. You can only pass a value.

Back to the original question. Let's see a struct example:

type My struct {
	A int
	B interface{}
	C io.Reader
}

You want to tell if the type of a field is interface{}. Acquire the reflect.Type of the struct type, then you can access the fields using Type.Field() or Type.FieldByName().

This gives you a value of type reflect.StructField which stores the type of the field.

So far so good. But what should we compare it to? interface{} is an interface type with 0 methods. You can't have (instantiate) a value of that type. You can only have values of concrete types, but yes, they may be wrapped in an interface type.

You could use Type.Kind, and compare it to reflect.Interface, which tells you if it's an interface, but this is true for all interface types. You could also check if it has 0 methods with Type.NumMethod(), which must be 0 for interface{}, but other interfaces could also have 0 methods...

You may use Type.Name, but since interface{} is a unnamed type, its name is the empty string &quot;&quot; (and there are other unnamed types). You may use Type.String() which returns &quot;interface {}&quot; for the empty interface:

t := reflect.TypeOf(My{})

for i := 0; i &lt; t.NumField(); i++ {
	f := t.Field(i)
	fmt.Printf(&quot;Field %q, type: %-12v, type name: %-8q, is interface{}: %v\n&quot;,
		f.Name, f.Type,
		f.Type.Name(),
		f.Type.String() == &quot;interface {}&quot;,
	)
}

Output (try it on the Go Playground):

Field &quot;A&quot;, type: int         , type name: &quot;int&quot;   , is interface{}: false
Field &quot;B&quot;, type: interface {}, type name: &quot;&quot;      , is interface{}: true
Field &quot;C&quot;, type: io.Reader   , type name: &quot;Reader&quot;, is interface{}: false

You might find this related question interesting / useful: https://stackoverflow.com/questions/36310538/identify-non-builtin-types-using-reflect/37292523#37292523

huangapple
  • 本文由 发表于 2017年1月17日 18:27:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/41694647.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定