亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用反射動態獲取指向結構的所有字段的指針

使用反射動態獲取指向結構的所有字段的指針

Go
慕婉清6462132 2023-03-07 11:06:35
我正在嘗試為 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,以便它可以在不同的數據庫模型中重用。
查看完整描述

1 回答

?
米脂

TA貢獻1836條經驗 獲得超3個贊

該錯誤表明您想要獲取其地址的值是不可尋址的。這是因為即使您將指針傳遞給GetSqlColumnToFieldMap(),您也會立即取消引用它并稍后使用非指針值。


這個值被包裝在一個interface{}when passed to中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]


查看完整回答
反對 回復 2023-03-07
  • 1 回答
  • 0 關注
  • 80 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號