2 回答

TA貢獻(xiàn)1793條經(jīng)驗(yàn) 獲得超6個(gè)贊
泛型可以用來實(shí)現(xiàn)這樣的事情,但 Go 不支持泛型。要在 Go 中做你想做的事,你需要使用反射。
您可以更改您的函數(shù)以采用 1 個(gè)附加參數(shù),reflect.Type例如,它指定應(yīng)加載各個(gè)行的值的類型。
然后,您可以使用reflect.New()創(chuàng)建此類型的新值并獲取指向它的指針。您可以使用從值中Value.Interface()獲取作為類型的指針值。這個(gè)包裝指針現(xiàn)在可以傳遞給.interface{}reflect.Valueinterface{}Rows.StructScan()
如果您希望結(jié)果切片包含非指針值,您可以使用reflect.Indirect()來獲取指向的值(以及另一個(gè)reflect.Interface()將結(jié)構(gòu)值提取為interface{})。
示例代碼:
func buildResults(query string, t reflect.Type) ([]interface{}, error) {
results := []interface{}{}
rows, err := sql.DB.Queryx(query)
if err != nil {
return results, err
}
defer rows.Close()
for rows.Next() {
val := reflect.New(t)
err := rows.StructScan(val.Interface())
if err != nil {
return results, err
}
i_ := reflect.Indirect(val)
result = append(result, i_.Interface())
}
err = rows.Err()
if err != nil {
return results, err
}
return results, nil
}
它的核心是for塊:
val := reflect.New(t) // A pointer to a new value (of type t)
err := rows.StructScan(val.Interface()) // Pass the pointer to StructScan
if err != nil {
return results, err
}
i_ := reflect.Indirect(val) // Dereference the pointer
result = append(result, i_.Interface()) // And add the non-pointer to the result slice
以下是測(cè)試它的方法:
type BetaKey struct {
Id string
Name string
}
type AlphaKey struct {
Id string
Source string
}
r, err := buildResults("", reflect.TypeOf(AlphaKey{}))
fmt.Printf("%T %+v %v\n", r[0], r, err)
r, err = buildResults("", reflect.TypeOf(BetaKey{}))
fmt.Printf("%T %+v %v\n", r[0], r, err)
輸出:
main.AlphaKey [{Id:aa Source:asource} {Id:aa Source:asource} {Id:aa Source:asource}] <nil>
main.BetaKey [{Id:aa Name:aname} {Id:aa Name:aname} {Id:aa Name:aname}] <nil>
在Go Playground上嘗試一下。
筆記:
上面的解決方案將返回一個(gè)類型的值,[]interface{}其元素將是靜態(tài)類型,interface{}而它們的動(dòng)態(tài)類型將是reflect.Type參數(shù)指定的類型。因此,例如,如果您使用以下類型調(diào)用它:
bt := reflect.TypeOf(BetaKey{})
結(jié)果切片中的值將具有動(dòng)態(tài)類型,BetaKey因此您可以像這樣安全地鍵入斷言它們:
results, err := buildResults("some query", bt)
if err == nil {
for _, v := range results {
key := v.(BetaKey)
// key is of type BetaKey, you may use it like so
}
} else {
// handle error
}

TA貢獻(xiàn)1893條經(jīng)驗(yàn) 獲得超10個(gè)贊
我用 json 寫了一個(gè)小例子,而不是 sql 行。您可以嘗試從此代碼進(jìn)行開發(fā):
package main
import (
"fmt"
"reflect"
"encoding/json"
)
type A struct {
AField int `json:"a"`
}
type B struct {
BField string `json:"b"`
}
func build(str string, typ reflect.Type) interface{} {
results := reflect.MakeSlice(reflect.SliceOf(typ), 0, 10)
for i:=0; i < 5; i++ {
res := reflect.New(typ)
json.Unmarshal([]byte(str), res.Interface())
results = reflect.Append(results, res.Elem())
}
return results.Interface();
}
func main() {
a := build("{ \"a\": 15 }", reflect.TypeOf(&A{}))
fmt.Printf("%T : %V\n", a, a)
b := build("{ \"b\": \"my string\" }", reflect.TypeOf(&B{}))
fmt.Printf("%T : %V\n", b, b)
}
- 2 回答
- 0 關(guān)注
- 145 瀏覽
添加回答
舉報(bào)