Here are my types
type MyTypeFlagSkel struct {
Name string
Short string
HelpMsg string
NeedsBinding bool
Interactive bool
RegexEval *RegexPattern
}
type MyTypeFlag interface {
GetName() string
BindPersistentFlag(cobraCommand *cobra.Command)
IsInteractive() bool
GetDefaultValue() interface{}
GetHelpMsg() string
GetRegexEval() *RegexPattern
}
type MyTypeFlagString struct {
Value string
DefaultValue string
}
type MyTypeFlagStringSlice struct {
Value []string
DefaultValue string
}
type MyTypeFlagBool struct {
Value bool
DefaultValue bool
}
type MyTypeCompositeFlagString struct {
MyTypeFlagSkel
MyTypeFlagString
}
type MyTypeCompositeFlagStringSlice struct {
MyTypeFlagSkel
MyTypeFlagStringSlice
}
type MyTypeCompositeFlagBool struct {
MyTypeFlagSkel
MyTypeFlagBool
}
For brevity reasons, omitting implementations of MyTypeFlag
interface methods by all Composite
types.
Here is a type composed of such types as the ones above
type ChartOpts struct {
Name MyTypeCompositeFlagString
Keywords MyTypeCompositeFlagStringSlice
Interactive MyTypeCompositeFlagBool
}
And here is a function reflecting on its argument and trying to set its fields (
func FillInFlagsInteractively(e interface{}) error {
var defaultValueMsg string
fields := reflect.TypeOf(e)
values := reflect.ValueOf(e)
num := fields.Elem().NumField()
for i := 0; i < num; i++ {
switch v := values.Elem().Field(i).Interface().(type) {
case MyTypeFlag:
if v.IsInteractive() {
if v.GetDefaultValue() == "" {
defaultValueMsg = "No default (or empty) value for this input"
} else {
defaultValueMsg = fmt.Sprintf("Default value that will be used is %v (press Enter to accept the default value)", v.GetDefaultValue())
}
prompt := fmt.Sprintf("Please fill in %s - %s: ", strings.ToLower(v.GetHelpMsg()), defaultValueMsg)
userInput, err := InteractiveInput(prompt, v.GetDefaultValue(), v.GetRegexEval())
if err != nil {
return err
}
if userInput == "" {
fmt.Println("No user input provided, will proceed with default or auto-generated value")
}
// second level switch to handle each case distinctively depending on the flag type
switch fType := v.(type) {
case MyTypeCompositeFlagString:
s, ok := userInput.(string)
if !ok {
log.Printf("Erroneous input type:%T and input value: %v\n", userInput, userInput)
return ErrUnexpectedInput
}
fType.Value = s
case MyTypeCompositeFlagStringSlice:
s, ok := userInput.(string)
if !ok {
log.Printf("Erroneous input type:%T and input value: %v\n", userInput, userInput)
return ErrUnexpectedInput
}
sSlice := strings.Split(s, ",")
for i, v := range sSlice {
sSlice[i] = strings.TrimSpace(v)
}
fType.Value = sSlice
case MyTypeCompositeFlagBool:
s, ok := userInput.(bool)
if !ok {
log.Printf("Erroneous input type:%T and input value: %v\n", userInput, userInput)
return ErrUnexpectedInput
}
fType.Value = s
default:
return ErrUnhandledType
}
}
default:
return ErrUnhandledType
}
}
return nil
}
I am calling MyFunc
and passing a pointer to a ChartOpts
variable.
The problem is that after making the function call, and despite setting the field of the embedded struct as in fType.Value = s
the original struct seems unaffected.
Why does the fType = s
has no impact on the original struct?
Aucun commentaire:
Enregistrer un commentaire