为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
白猪掌柜的 2022-05-23 18:00:50
我试图用指针构造 Book 结构的切片,但我无法通过 Go 中的反射使其工作。[]*Book 结构指针的 Book 切片,请注意,scanResults 方法可能会接收任何类型的切片,而不仅仅是 Book 结构。所以我希望在运行时动态构建一个切片你能告诉我我在下面的代码片段中出错了吗?package mainimport (  "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
查看完整描述

1 回答

?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

你快到了。这是一些带有注释的工作代码:


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

}


查看完整回答
反对 回复 2022-05-23
  • 1 回答
  • 0 关注
  • 151 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信