diff --git a/defaults.go b/defaults.go index 3f77fd5..bdb0e9a 100644 --- a/defaults.go +++ b/defaults.go @@ -38,7 +38,7 @@ func Set(ptr interface{}) error { } } } - + callSetter(ptr) return nil } @@ -133,13 +133,11 @@ func setField(field reflect.Value, defaultVal string) error { } field.Set(ref.Elem().Convert(field.Type())) case reflect.Struct: - ref := reflect.New(field.Type()) if defaultVal != "" && defaultVal != "{}" { - if err := json.Unmarshal([]byte(defaultVal), ref.Interface()); err != nil { + if err := json.Unmarshal([]byte(defaultVal), field.Addr().Interface()); err != nil { return err } } - field.Set(ref.Elem()) case reflect.Ptr: field.Set(reflect.New(field.Type().Elem())) } @@ -150,13 +148,9 @@ func setField(field reflect.Value, defaultVal string) error { setField(field.Elem(), defaultVal) callSetter(field.Interface()) case reflect.Struct: - ref := reflect.New(field.Type()) - ref.Elem().Set(field) - if err := Set(ref.Interface()); err != nil { + if err := Set(field.Addr().Interface()); err != nil { return err } - callSetter(ref.Interface()) - field.Set(ref.Elem()) case reflect.Slice: for j := 0; j < field.Len(); j++ { if err := setField(field.Index(j), defaultVal); err != nil { @@ -176,11 +170,15 @@ func shouldInitializeField(field reflect.Value, tag string) bool { switch field.Kind() { case reflect.Struct: return true + case reflect.Ptr: + if !field.IsNil() && field.Elem().Kind() == reflect.Struct { + return true + } case reflect.Slice: return field.Len() > 0 || tag != "" } - return (tag != "") + return tag != "" } // CanUpdate returns true when the given value is an initial value of its type diff --git a/defaults_test.go b/defaults_test.go index b04ca6b..ec20c65 100644 --- a/defaults_test.go +++ b/defaults_test.go @@ -389,3 +389,52 @@ func TestCanUpdate(t *testing.T) { } } } + +type Child struct { + Name string `default:"Tom"` + Age int `default:"20"` +} + +type Parent struct { + Child *Child +} + +func TestPointerStructMember(t *testing.T) { + m := Parent{Child: &Child{Name: "Jim"}} + Set(&m) + if m.Child.Age != 20 { + t.Errorf("20 is expected") + } +} + +type Main struct { + MainInt int `default:"-"` + *Other `default:"{}"` +} + +type Other struct { + OtherInt int `default:"-"` +} + +func (s *Main) SetDefaults() { + if CanUpdate(s.MainInt) { + s.MainInt = 1 + } +} + +func (s *Other) SetDefaults() { + if CanUpdate(s.OtherInt) { + s.OtherInt = 1 + } +} + +func TestDefaultsSetter(t *testing.T) { + main := &Main{} + Set(main) + if main.OtherInt != 1 { + t.Errorf("expected 1 for OtherInt, got %d", main.OtherInt) + } + if main.MainInt != 1 { + t.Errorf("expected 1 for MainInt, got %d", main.MainInt) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4f06bae --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/creasty/defaults + +go 1.11