From ed057dea0ef2b2949f83edbb668d832cbf14b5d6 Mon Sep 17 00:00:00 2001 From: Vladimir Babin Date: Sun, 23 Aug 2026 11:20:52 +0300 Subject: [PATCH] fix: recurse into []*struct with Deep struct-to-map decoding decodeMapFromStruct only mapped slices whose element Kind is reflect.Struct into []map[string]any under Deep. A slice of pointers to structs ([]*T) has element Kind reflect.Ptr, so it fell through to the default branch and was copied verbatim, leaving raw *T pointers in the output map while the equivalent []T field was correctly turned into []map[string]any. Treat []*T (pointer-to-struct element) the same as []T. Extends the existing TestDecode_structArrayDeepMap with a []*SourceChild field that fails before this change and passes after. Fixes #196. --- mapstructure.go | 11 +++++++---- mapstructure_test.go | 9 +++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/mapstructure.go b/mapstructure.go index 9087fd96..22cfdf91 100644 --- a/mapstructure.go +++ b/mapstructure.go @@ -1259,11 +1259,14 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re case reflect.Slice: if deep { var childType reflect.Type - switch v.Type().Elem().Kind() { - case reflect.Struct: + elemType := v.Type().Elem() + // Recurse into slices of structs and slices of pointers to + // structs alike, so []*T maps the same way []T does. + if elemType.Kind() == reflect.Struct || + (elemType.Kind() == reflect.Ptr && elemType.Elem().Kind() == reflect.Struct) { childType = reflect.TypeOf(map[string]any{}) - default: - childType = v.Type().Elem() + } else { + childType = elemType } sType := reflect.SliceOf(childType) diff --git a/mapstructure_test.go b/mapstructure_test.go index baf40dfe..c6b3a416 100644 --- a/mapstructure_test.go +++ b/mapstructure_test.go @@ -3865,6 +3865,7 @@ func TestDecode_structArrayDeepMap(t *testing.T) { type SourceParent struct { ChildrenA []SourceChild `mapstructure:"children-a,deep"` ChildrenB *[]SourceChild `mapstructure:"children-b,deep"` + ChildrenC []*SourceChild `mapstructure:"children-c,deep"` } var target map[string]any @@ -3878,6 +3879,10 @@ func TestDecode_structArrayDeepMap(t *testing.T) { {String: "one"}, {String: "two"}, }, + ChildrenC: []*SourceChild{ + {String: "one"}, + {String: "two"}, + }, } if err := Decode(source, &target); err != nil { @@ -3893,6 +3898,10 @@ func TestDecode_structArrayDeepMap(t *testing.T) { {"some-string": "one"}, {"some-string": "two"}, }, + "children-c": []map[string]any{ + {"some-string": "one"}, + {"some-string": "two"}, + }, } if !reflect.DeepEqual(target, expected) {