diff --git a/nreflect/util.go b/nreflect/util.go index f26dd0d..ab9cfdb 100644 --- a/nreflect/util.go +++ b/nreflect/util.go @@ -28,6 +28,50 @@ func Indirect(v reflect.Value) reflect.Value { return v } +// IndirectAddr walks down v allocating pointers as needed, +// until it gets to a non-pointer. +func IndirectAddr(v reflect.Value) reflect.Value { + v0 := v + haveAddr := false + + // 如果v是命名类型并且可寻址(非指针) + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // 从接口加载值,但前提是结果可有效寻址。 + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && e.Elem().Kind() == reflect.Ptr { + haveAddr = false + v = e + continue + } + } + if v.Kind() != reflect.Ptr { + break + } + // 防止无限循环,v有可能是是指向其自身地址的接口: + // var v any + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() && v.CanSet() { + v.Set(reflect.New(v.Type().Elem())) + } + if haveAddr { + v = v0 // 返回原始值,如果可寻址 + haveAddr = false + } else { + v = v.Elem() + } + } + return v +} + // Len get reflect value length func Len(v reflect.Value) int { v = reflect.Indirect(v)