[英]Assigning to type definition using reflection in Go
I have setup a type called Provider
that defines an integer:我设置了一个名为
Provider
的类型,它定义了一个 integer:
type Provider int
func (enum *Provider) Scan(raw interface{}) error {
*enum = Provider(int(raw))
}
If I create an object, Foo, with a Provider
field, like this:如果我创建一个带有
Provider
字段的 object,Foo,如下所示:
type Foo struct {
Code Provider
Value string
}
foo := &Foo {
Code: Provider(0),
Value: "derp",
}
var scnr sql.Scanner
scannerType := reflect.TypeOf(&scnr).Elem()
tType := reflect.TypeOf(foo)
tField := tType.Field(0)
fmt.Printf("Field %s, of type %s, kind %s\n",
tField.Name, tField.Type, tField.Type.Kind())
When I run this code, I get that the field is of type Provider
and its Kind is int
.当我运行这段代码时,我知道该字段的类型是
Provider
并且它的 Kind 是int
。 However, I cannot assign an int to a Provider using reflection because this will fail:但是,我不能使用反射将 int 分配给 Provider,因为这将失败:
getInteger() interface{} {
return 1
}
fValue := reflect.ValueOf(foo).Elem()
vField := fValue.Field(0)
vField.Set(reflect.ValueOf(getInteger())) // panic: reflect.Set: value of type int is not assignable to type Provider
The normal solution to this would be to do reflect.ValueOf(Provider(getInteger().(int)))
, however, this won't work because vField
is set inside of a loop that iterates over a structure's fields and therefore will have a different type.对此的正常解决方案是执行
reflect.ValueOf(Provider(getInteger().(int)))
,但是,这不起作用,因为vField
设置在迭代结构字段的循环内,因此将具有一种不同的类型。 Essentially, I would like a way to detect that vField
is a definition of int
(ie. Provider
) rather than an int
, itself;本质上,我想要一种方法来检测
vField
是int
的定义(即Provider
)而不是int
本身; so I could use reflection to cast the integer value to Provider
when I set it.所以我可以在设置时使用反射将 integer 值转换为
Provider
。
Is there a way I can make this work?有没有办法让这个工作?
The kind and type are not identical terms.种类和类型不是相同的术语。 Kind of both
int
and Provider
is int
because Provider
has int
as its underlying type. int
和Provider
的种类都是int
,因为Provider
将int
作为其基础类型。 But the type Provider
is not identical to int
.但是类型
Provider
与int
不同。 What you have is a type definition , but not a type alias.您拥有的是类型定义,而不是类型别名。 Those are 2 different things.
这是两件不同的事情。 See Confused about behavior of type aliases for details.
有关详细信息,请参阅对类型别名的行为感到困惑。
The type of Foo.Code
field is Provider
, you can only assign a value of type Provider
to it: Foo.Code
字段的类型是Provider
,您只能为其分配一个Provider
类型的值:
vField.Set(reflect.ValueOf(Provider(1)))
This works.这行得通。
Note that reflection or not, you can't assign int
to Foo.Code
:请注意,无论是否反射,您都不能将
int
分配给Foo.Code
:
var i int = 3
var foo Foo
foo.Code = i // Error!
The above has compile time error:以上有编译时错误:
error: cannot use i (variable of type int) as type Provider in assignment
错误:不能在赋值中使用 i(int 类型的变量)作为类型 Provider
What may be confusing is that using a constant works:可能令人困惑的是,使用常量有效:
var foo Foo
foo.Code = 3 // Works!
This is because 3
is an untyped constant representable by a value of type Provider
, so the constant will be converted to Provider
.这是因为
3
是一个无类型的常量,可以由Provider
类型的值表示,因此该常量将被转换为Provider
。
I ended up using the Convert
function in conjunction with the Assignable
function to do my check:我最终使用
Convert
function 和Assignable
function 进行检查:
// Get value to assign and its type
vValue := reflect.ValueOf(getInteger())
tValue := vValue.Type()
// Check if the field can be assigned the value; if it can then do so
// Otherwise, check if a conversion can be assigned
vType := vField.Type()
if tValue.AssignableTo(vType) {
vField.Set(vValue)
} else if vValue.CanConvert(vType) {
vField.Set(vValue.Convert(vType))
}
This fixed my issue.这解决了我的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.