@@ -90,11 +90,12 @@ func (m *structCache) Fields(typ reflect.Type, tag string) *fields {
9090//------------------------------------------------------------------------------
9191
9292type field struct {
93- encoder encoderFunc
94- decoder decoderFunc
95- name string
96- index []int
97- omitEmpty bool
93+ encoder encoderFunc
94+ decoder decoderFunc
95+ name string
96+ index []int
97+ omitEmpty bool
98+ maybeZeroer bool // true when the field type implements isZeroer
9899}
99100
100101func (f * field ) Omit (e * Encoder , strct reflect.Value ) bool {
@@ -103,7 +104,7 @@ func (f *field) Omit(e *Encoder, strct reflect.Value) bool {
103104 return true
104105 }
105106 forced := e .flags & omitEmptyFlag != 0
106- return (f .omitEmpty || forced ) && e .isEmptyValue ( v )
107+ return (f .omitEmpty || forced ) && e .isEmptyValueHint ( v , f . maybeZeroer )
107108}
108109
109110func (f * field ) EncodeValue (e * Encoder , strct reflect.Value ) error {
@@ -211,9 +212,10 @@ func getFields(typ reflect.Type, fallbackTag string) *fields {
211212 }
212213
213214 field := & field {
214- name : tag .Name ,
215- index : f .Index ,
216- omitEmpty : omitEmpty || tag .HasOption ("omitempty" ),
215+ name : tag .Name ,
216+ index : f .Index ,
217+ omitEmpty : omitEmpty || tag .HasOption ("omitempty" ),
218+ maybeZeroer : f .Type .Implements (isZeroerType ) || reflect .PtrTo (f .Type ).Implements (isZeroerType ),
217219 }
218220
219221 if tag .HasOption ("intern" ) {
@@ -331,7 +333,13 @@ type isZeroer interface {
331333 IsZero () bool
332334}
333335
336+ var isZeroerType = reflect .TypeOf ((* isZeroer )(nil )).Elem ()
337+
334338func (e * Encoder ) isEmptyValue (v reflect.Value ) bool {
339+ return e .isEmptyValueHint (v , true )
340+ }
341+
342+ func (e * Encoder ) isEmptyValueHint (v reflect.Value , maybeZeroer bool ) bool {
335343 kind := v .Kind ()
336344
337345 for kind == reflect .Interface {
@@ -340,10 +348,13 @@ func (e *Encoder) isEmptyValue(v reflect.Value) bool {
340348 }
341349 v = v .Elem ()
342350 kind = v .Kind ()
351+ maybeZeroer = true // dynamic type — must check at runtime
343352 }
344353
345- if z , ok := v .Interface ().(isZeroer ); ok {
346- return nilable (kind ) && v .IsNil () || z .IsZero ()
354+ if maybeZeroer {
355+ if z , ok := v .Interface ().(isZeroer ); ok {
356+ return nilable (kind ) && v .IsNil () || z .IsZero ()
357+ }
347358 }
348359
349360 switch kind {
0 commit comments