diff options
author | Rob Pike <r@golang.org> | 2021-10-24 14:11:07 +1100 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2021-10-29 02:11:42 +0000 |
commit | 33c392f72d16163eb0795b3d61b2196ac21e1799 (patch) | |
tree | 2121c6ed2c08c00b93f3eec8f27d950dae6c1091 /src/reflect/value.go | |
parent | af05d8be3d9dd566b2ce3ff5344258314f128ff6 (diff) | |
download | go-33c392f72d16163eb0795b3d61b2196ac21e1799.tar.gz go-33c392f72d16163eb0795b3d61b2196ac21e1799.zip |
reflect: add FieldByIndexErr
This new function, although different in signature from other
reflect functions, allows the caller to avoid the panic caused by
nil embedded fields in calls to FieldByIndex.
Fixes #48218
Change-Id: I447f135bb789148c27ae3f2f23dcf43094f4c1de
Reviewed-on: https://go-review.googlesource.com/c/go/+/357962
Trust: Rob Pike <r@golang.org>
Run-TryBot: Rob Pike <r@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/reflect/value.go')
-rw-r--r-- | src/reflect/value.go | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go index 618d38893e..90edf8e31d 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -5,6 +5,7 @@ package reflect import ( + "errors" "internal/abi" "internal/goarch" "internal/itoa" @@ -1232,7 +1233,8 @@ func (v Value) Field(i int) Value { } // FieldByIndex returns the nested field corresponding to index. -// It panics if v's Kind is not struct. +// It panics if evaluation requires stepping through a nil +// pointer or a field that is not a struct. func (v Value) FieldByIndex(index []int) Value { if len(index) == 1 { return v.Field(index[0]) @@ -1252,6 +1254,29 @@ func (v Value) FieldByIndex(index []int) Value { return v } +// FieldByIndexErr returns the nested field corresponding to index. +// It returns an error if evaluation requires stepping through a nil +// pointer, but panics if it must step through a field that +// is not a struct. +func (v Value) FieldByIndexErr(index []int) (Value, error) { + if len(index) == 1 { + return v.Field(index[0]), nil + } + v.mustBe(Struct) + for i, x := range index { + if i > 0 { + if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct { + if v.IsNil() { + return Value{}, errors.New("reflect: indirection through nil pointer to embedded struct field " + v.typ.Elem().Name()) + } + v = v.Elem() + } + } + v = v.Field(x) + } + return v, nil +} + // FieldByName returns the struct field with the given name. // It returns the zero Value if no field was found. // It panics if v's Kind is not struct. |