diff --git a/os/gstructs/gstructs_field.go b/os/gstructs/gstructs_field.go index 12213b73d44..639291fd25c 100644 --- a/os/gstructs/gstructs_field.go +++ b/os/gstructs/gstructs_field.go @@ -92,9 +92,26 @@ func (f *Field) OriginalKind() reflect.Kind { reflectType = reflectType.Elem() reflectKind = reflectType.Kind() } + return reflectKind } +// OriginalValue retrieves and returns the original reflect.Value of Field `f`. +func (f *Field) OriginalValue() reflect.Value { + var ( + reflectValue = f.Value + reflectType = reflectValue.Type() + reflectKind = reflectType.Kind() + ) + + for reflectKind == reflect.Ptr && !f.IsNil() { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Type().Kind() + } + + return reflectValue +} + // IsEmpty checks and returns whether the value of this Field is empty. func (f *Field) IsEmpty() bool { return empty.IsEmpty(f.Value) diff --git a/util/gutil/gutil_struct.go b/util/gutil/gutil_struct.go index dee73648119..f0b87cbcd90 100644 --- a/util/gutil/gutil_struct.go +++ b/util/gutil/gutil_struct.go @@ -83,12 +83,20 @@ func FillStructWithDefault(structPtr interface{}) error { } fields, err := gstructs.Fields(gstructs.FieldsInput{ Pointer: reflectValue, - RecursiveOption: gstructs.RecursiveOptionNone, + RecursiveOption: gstructs.RecursiveOptionEmbedded, }) if err != nil { return err } for _, field := range fields { + if field.OriginalKind() == reflect.Struct { + err := FillStructWithDefault(field.OriginalValue().Addr()) + if err != nil { + return err + } + continue + } + if defaultValue := field.TagDefault(); defaultValue != "" { if field.IsEmpty() { field.Value.Set(reflect.ValueOf( @@ -97,5 +105,6 @@ func FillStructWithDefault(structPtr interface{}) error { } } } + return nil } diff --git a/util/gutil/gutil_z_unit_struct_test.go b/util/gutil/gutil_z_unit_struct_test.go index fe4b62e9753..d9ebde8057b 100755 --- a/util/gutil/gutil_z_unit_struct_test.go +++ b/util/gutil/gutil_z_unit_struct_test.go @@ -39,17 +39,44 @@ func Test_StructToSlice(t *testing.T) { func Test_FillStructWithDefault(t *testing.T) { gtest.C(t, func(t *gtest.T) { - type A struct { - V1 int `d:"1.01"` - V2 string `d:"1.01"` - V3 float32 `d:"1.01"` + type myInt int + type Inner1 struct { + I1V1 int + I1V2 bool `d:"true"` } - a := A{} - err := gutil.FillStructWithDefault(&a) + type Inner2 struct { + I2V1 float64 `d:"1.01"` + } + type Inner3 struct { + Inner1 Inner1 + I3V1 myInt `d:"1"` + } + type Inner4 struct { + } + type Outer struct { + O1 int `d:"1.01"` + O2 string `d:"1.01"` + O3 float32 `d:"1.01"` + *Inner1 + O4 bool `d:"true"` + Inner2 + Inner3 Inner3 + Inner4 *Inner4 + } + + outer := Outer{} + err := gutil.FillStructWithDefault(&outer) t.AssertNil(err) - t.Assert(a.V1, `1`) - t.Assert(a.V2, `1.01`) - t.Assert(a.V3, `1.01`) + t.Assert(outer.O1, 1) + t.Assert(outer.O2, `1.01`) + t.Assert(outer.O3, `1.01`) + t.Assert(outer.O4, true) + t.Assert(outer.Inner1, nil) + t.Assert(outer.Inner2.I2V1, `1.01`) + t.Assert(outer.Inner3.I3V1, 1) + t.Assert(outer.Inner3.Inner1.I1V1, 0) + t.Assert(outer.Inner3.Inner1.I1V2, true) + t.Assert(outer.Inner4, nil) }) }