mercredi 5 août 2020

Unable to set struct field after iterating within its fields using reflection

Here are my types

type MyTypeFlagSkel struct {
    Name         string
    Short        string
    HelpMsg      string
    NeedsBinding bool
    Interactive  bool
    RegexEval    *RegexPattern
}

type MyTypeFlag interface {
    BindPersistentFlag(cobraCommand *cobra.Command)
    IsInteractive() bool
    GetDefaultValue() interface{}
    GetHelpMsg() string
    GetRegexEval() *RegexPattern
}

type MyTypeFlagString struct {
    Value        string
    DefaultValue string
}


// -----------------------------------------------------------------------------
// String Flag
type MyTypeCompositeFlagString struct {
    MyTypeFlagSkel
    MyTypeFlagString
}

(all methods of MyTypeFlag are implemented by MyTypeComposeFlagString)

I have created the following function to iterate through (another type of) a struct that encompasses fields of the above types, as in

type MyOpts struct {
    Name             MyTypeCompositeFlagString
    Repo             MyTypeCompositeFlagString
}

the function goes more or less like:

func FillInFlagsInteractively(e interface{}) error {
    var defaultValueMsg string

    fields := reflect.TypeOf(e)
    values := reflect.ValueOf(e)
    num := fields.NumField()
    for i := 0; i < num; i++ {
        switch v := values.Field(i).Interface().(type) {
        case MyTypeFlag:
            if v.IsInteractive() {
                fmt.Printf("%T\n", v.(MyTypeCompositeFlagString).Name)
                v.(MyTypeCompositeFlagString).Name = "foo"

However, despite the fact that I am able to get the field Name and print it in line

fmt.Printf("%T\n", v.(MyTypeCompositeFlagString).Name)

compiler prevents me from setting it in the following line:

v.(MyTypeCompositeFlagString).Name = "foo"

with the following error

cannot assign to v.(MyTypeCompositeFlagString).Name (value of type string)

why is that?

Notes (for what they are worth):

a) the function signature that accepts interface{} has to do with the fact I will be passing several kinds of types in the likes of MyOpts that however don't have any specific behavior so I could not tie to a method set and therefore an interface

b) since I need in place modification of MyOpts, I am passing a pointer to an MyOpts var when calling it (for what that matters)





Aucun commentaire:

Enregistrer un commentaire