How to dynamically create a struct with one less p

2019-06-12 10:12发布

问题:

Is there a way to copy a generic struct (i.e. a struct whose property names are unknown) and skip a single, known property?

Here is what I know:

  • The parameter to my function--I will call the parameter myData-- is of type interface{}.
  • myData is a struct.
  • myData has a known property path.
  • myData has anywhere from 0 to 6 or so other properties, none of which are known a priori.
  • Once I remove that path property, then the “leftover” is one of say 30 possible struct types.

So I want to strip path out of myData (or more accurately make a copy that omits path) so that various bits of generated code that try to coerce the struct to one of its possible types will be able to succeed.

I have found examples of copying a struct by reflection, but they typically create an empty struct of the same underlying type, then fill it in. So is it even possible to delete a property as I have outlined...?

回答1:

You can use reflect.StructOf to dynamically create structs from a list of fields.

package main

import (
    "fmt"
    "reflect"
)

type A struct {
    Foo string
    Bar int
    Baz bool // to be skipped
}

type B struct {
    Foo string
    Bar int
}

func main() {
    av := reflect.ValueOf(A{"hello", 123, true})

    fields := make([]reflect.StructField, 0)
    values := make([]reflect.Value, 0)
    for i := 0; i < av.NumField(); i++ {
        f := av.Type().Field(i)
        if f.Name != "Baz" {
            fields = append(fields, f)
            values = append(values, av.Field(i))
        }
    }

    typ := reflect.StructOf(fields)
    val := reflect.New(typ).Elem()
    for i := 0; i < len(fields); i++ {
        val.Field(i).Set(values[i])
    }

    btyp := reflect.TypeOf(B{})
    bval := val.Convert(btyp)

    b, ok := bval.Interface().(B)
    fmt.Println(b, ok)
}


标签: go reflection