[英]Get pointers to all fields of a struct dynamically using reflection
I'm trying to build a simple orm layer for golang.我正在尝试为 golang 构建一个简单的 orm 层。 Which would take a struct and generate the
cols []
which can then be passed to sql function rows.Scan(cols...)
which takes pointers of fields in the struct corresponding to each of the columns it has found in the result set这将采用一个结构并生成
cols []
然后可以将其传递给 sql function rows.Scan(cols...)
它采用结构中与它在结果集中找到的每一列相对应的字段指针
Here is my example struct这是我的示例结构
type ExampleStruct struct {
ID int64 `sql:"id"`
aID string `sql:"a_id"`
UserID int64 `sql:"user_id"`
And this is my generic ORM function这是我的通用 ORM function
func GetSqlColumnToFieldMap(model *ExampleStruct) map[string]interface{} {
typeOfModel := reflect.TypeOf(*model)
ValueOfModel := reflect.ValueOf(*model)
columnToDataPointerMap := make(map[string]interface{})
for i := 0; i < ValueOfModel.NumField(); i++ {
sql_column := typeOfModel.Field(i).Tag.Get("sql")
structValue := ValueOfModel.Field(i)
columnToDataPointerMap[sql_column] = structValue.Addr()
}
return columnToDataPointerMap
}
Once this method works fine i can use the map it generates to create an ordered list of sql pointers according to the column_names i get in rows() object However i get below error on the .Addr()
method call一旦此方法正常工作,我可以使用它生成的 map 根据我在 rows() 中获得的 column_names 创建一个有序的 sql 指针列表 object 但是我在
.Addr()
方法调用中遇到以下错误
panic: reflect.Value.Addr of unaddressable value [recovered]
panic: reflect.Value.Addr of unaddressable value
Is it not possible to do this?不可能这样做吗? Also in an ideal scenario i would want the method to take an interface instead of *ExampleStruct so that it can be reused across different db models.
同样在理想情况下,我希望该方法采用接口而不是 *ExampleStruct,以便它可以在不同的数据库模型中重用。
The error says the value whose address you want to get is unaddressable.该错误表明您想要获取其地址的值是不可寻址的。 This is because even though you pass a pointer to
GetSqlColumnToFieldMap()
, you immediately dereference it and work with a non-pointer value later on.这是因为即使您将指针传递给
GetSqlColumnToFieldMap()
,您也会立即取消引用它并稍后使用非指针值。
This value is wrapped in an interface{}
when passed to reflect.ValueOf()
, and values wrappped in interfaces are not addressable.当传递给
reflect.ValueOf()
时,此值被包装在interface{}
中,并且包装在接口中的值不可寻址。
You must not dereference the pointer, but instead use Type.Elem()
and Value.Elem()
to get the element type and pointed value.您不能取消引用指针,而是使用
Type.Elem()
和Value.Elem()
来获取元素类型和指向的值。
Something like this:是这样的:
func GetSqlColumnToFieldMap(model *ExampleStruct) map[string]interface{} {
t := reflect.TypeOf(model).Elem()
v := reflect.ValueOf(model).Elem()
columnToDataPointerMap := make(map[string]interface{})
for i := 0; i < v.NumField(); i++ {
sql_column := t.Field(i).Tag.Get("sql")
structValue := v.Field(i)
columnToDataPointerMap[sql_column] = structValue.Addr()
}
return columnToDataPointerMap
}
With this simple change it works, And it doesn't depend on the parameter type, you may change it to interface{}
and pass any struct pointers.通过这个简单的更改它就可以工作,并且它不依赖于参数类型,您可以将其更改为
interface{}
并传递任何结构指针。
func GetSqlColumnToFieldMap(model interface{}) map[string]interface{} {
// ...
}
Testing it:测试它:
type ExampleStruct struct {
ID int64 `sql:"id"`
AID string `sql:"a_id"`
UserID int64 `sql:"user_id"`
}
type Point struct {
X int `sql:"x"`
Y int `sql:"y"`
}
func main() {
fmt.Println(GetSqlColumnToFieldMap(&ExampleStruct{}))
fmt.Println(GetSqlColumnToFieldMap(&Point{}))
}
Output (try it on the Go Playground ): Output(在Go 游乐场试试):
map[a_id:<*string Value> id:<*int64 Value> user_id:<*int64 Value>]
map[x:<*int Value> y:<*int Value>]
Note that Value.Addr()
returns the address wrapped in a reflect.Value
.请注意,
Value.Addr()
返回包裹在reflect.Value
中的地址。 To "unwrap" the pointer, use Value.Interface()
:要“展开”指针,请使用
Value.Interface()
:
func GetSqlColumnToFieldMap(model interface{}) map[string]interface{} {
t := reflect.TypeOf(model).Elem()
v := reflect.ValueOf(model).Elem()
m := make(map[string]interface{})
for i := 0; i < v.NumField(); i++ {
colName := t.Field(i).Tag.Get("sql")
field := v.Field(i)
m[colName] = field.Addr().Interface()
}
return m
}
This will output (try it on the Go Playground ):这将是 output(在Go 游乐场上试试):
map[a_id:0xc00007e008 id:0xc00007e000 user_id:0xc00007e018]
map[x:0xc000018060 y:0xc000018068]
For an in-depth introduction to reflection, please read blog post: The Laws of Reflection关于反射的深入介绍,请阅读博文: The Laws of Reflection
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.