我正在嘗試為 golang 構建一個簡單的 orm 層。這將采用一個結構并生成cols []它,然后可以將其傳遞給sql函式
rows.Scan(cols...),該函式采用結構中與它在結果集中找到的每個列相對應的欄位的指標
這是我的示例結構
type ExampleStruct struct {
ID int64 `sql:"id"`
aID string `sql:"a_id"`
UserID int64 `sql:"user_id"`
這是我的通用 ORM 函式
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
}
一旦這個方法作業正常,我可以使用它生成的映射來根據我在 rows() 物件中得到的 column_names 創建一個有序的 sql 指標串列但是我在.Addr()方法呼叫中得到以下錯誤
panic: reflect.Value.Addr of unaddressable value [recovered]
panic: reflect.Value.Addr of unaddressable value
這不可能嗎?同樣在理想情況下,我希望該方法采用介面而不是 *ExampleStruct,以便可以在不同的資料庫模型中重用它。
uj5u.com熱心網友回復:
該錯誤表示您要獲取其地址的值是不可尋址的。這是因為即使您將指標傳遞給GetSqlColumnToFieldMap(),您也會立即取消參考它并稍后使用非指標值。
這個值被包裹在一個interface{}when 傳遞給 中reflect.ValueOf(),并且包裹在介面中的值是不可尋址的。
您不能取消參考指標,而是使用Type.Elem()andValue.Elem()來獲取元素型別和指向的值。
像這樣的東西:
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
}
有了這個簡單的改變,它就可以作業了!而且它不依賴于引數型別,您可以將其更改為interface{}并傳遞任何結構指標。
func GetSqlColumnToFieldMap(model interface{}) map[string]interface{} {
// ...
}
測驗它:
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{}))
}
輸出(在Go Playground上試試):
map[a_id:<*string Value> id:<*int64 Value> user_id:<*int64 Value>]
map[x:<*int Value> y:<*int Value>]
請注意,它Value.Addr()回傳包裹在reflect.Value. 要“解包”指標,請使用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
}
這將輸出(在Go Playground上嘗試):
map[a_id:0xc00007e008 id:0xc00007e000 user_id:0xc00007e018]
map[x:0xc000018060 y:0xc000018068]
有關反射的深入介紹,請閱讀博客文章:反射定律
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/442997.html
上一篇:如何將中間件用于特定路由等?
下一篇:附加到切片-golang
