如何使用反射动态构造结构切片

我试图用指针构造 Book 结构的切片,但我无法通过 Go 中的反射使其工作。


[]*Book 结构指针的 Book 切片,请注意,scanResults 方法可能会接收任何类型的切片,而不仅仅是 Book 结构。所以我希望在运行时动态构建一个切片


你能告诉我我在下面的代码片段中出错了吗?


package main


import (

  "reflect"

"errors"

"fmt"

)


type Book struct {

    Id    int

    Title string

    Price float32

}


func main() {

    var dest []*Book

    scanResults(&dest)

}


func scanResults(dest interface{}) error{

   resultsFromExternalSource := []interface{}{10 , "user-name" , float32(22)}


    value := reflect.ValueOf(dest)

    if value.Kind() != reflect.Ptr {

        return errors.New("must pass a pointer, not a value, to scan results into struct destination")

    }


    sliceElement := reflect.TypeOf(dest).Elem()

    if sliceElement.Kind() != reflect.Slice {

        return fmt.Errorf("expected %s but got %s", reflect.Slice, sliceElement.Kind())

    }


    structPtr := sliceElement.Elem()

    if structPtr.Kind() != reflect.Ptr {

        return fmt.Errorf("expected %s but got %s", reflect.Ptr, structPtr.Kind())

    }


    structElemType := reflect.TypeOf(structPtr).Elem()

    if structElemType.Kind() != reflect.Struct {

        return fmt.Errorf("expected %s but got %s", reflect.Struct, structElemType.Kind())

    }


 structRecordInterface := reflect.New(structElemType).Elem().Interface() // create a new struct

            structRecordType := reflect.TypeOf(structRecordInterface)

            structRecordValue := reflect.ValueOf(structRecordType)


    for i, result := range resultsFromExternalSource {




                if structRecordValue.Field(i).CanSet() {

                    structRecordValue.Field(i).Set(reflect.ValueOf(result))

                } else {

                    varName := structRecordType.Field(i).Name

                    varType := structRecordType.Field(i).Type

                    return fmt.Errorf("cannot scan results into passed struct destination as the struct field %v with %v type is not settable", varName, varType)

                }

       }

     return nil


}

https://play.golang.org/p/O9j4RobQqMy


白猪掌柜的
浏览 152回答 1
1回答

凤凰求蛊

你快到了。这是一些带有注释的工作代码:var errBadArg = errors.New("must pass pointer to slice of pointer to struct")func scanResults(dest interface{}) error {    resultsFromExternalSource := [][]interface{}{        {10, "user-name", float32(22)},        {20, "i-love-reflect", float32(100)},    }    // Get reflect.Value for the destination confirm that    // the destination is a pointer to a slice of pointers    // to a struct. The tests can be omitted if it's acceptable    // to panic on bad input argument.    destv := reflect.ValueOf(dest)    if destv.Kind() != reflect.Ptr {        return errBadArg    }    // Deference the pointer to get the slice.    destv = destv.Elem()    if destv.Kind() != reflect.Slice {        return errBadArg    }    elemt := destv.Type().Elem()    if elemt.Kind() != reflect.Ptr {        return errBadArg    }    // "deference" the element type to get the struct type.    elemt = elemt.Elem()     if elemt.Kind() != reflect.Struct {        return errBadArg    }    // For each row in the result set...    for j, row := range resultsFromExternalSource {        // Return error if more columns than fields in struct.        if len(row) > elemt.NumField() {            return errors.New("result larger than struct")        }        // Allocate a new slice element.        elemp := reflect.New(elemt)        // Dereference the pointer for field access.        elemv := elemp.Elem()        for i, col := range row {            fieldv := elemv.Field(i)            colv := reflect.ValueOf(col)            // Check to see if assignment to field will work            if !colv.Type().AssignableTo(fieldv.Type()) {                return fmt.Errorf("cannot assign %s to %s in row %d column %d", colv.Type(), fieldv.Type(), j, i)            }            // Set the field.            fieldv.Set(colv)        }        // Append element to the slice.        destv.Set(reflect.Append(destv, elemp))    }    return nil}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go