package reflux import ( "encoding/json" "errors" "fmt" "reflect" "strconv" "unsafe" "git.fsdpf.net/go/reflux/valuex" "github.com/spf13/cast" ) // rfx 是 R 接口的实现。 // // 它的内部表示只有三个字段(24 字节), 而不是一个 reflect.Value: // - td: 当前值的类型布局描述符(全局缓存, 不重复构建) // - ptr: 指向一个 td.rtype 类型值的地址 // - writable: 该地址是否允许写入 // // 见 unsafeptr.go 顶部的不变式 I1~I4。 type rfx struct { td *rfxTypeDesc ptr unsafe.Pointer writable bool // ptrRoot 标记"这个 rfx 是由 New(&x) 直接构造的根"。 // reflux 的 rfx.value 在这种情况下存的是**指针**本身, 所以 Raw() 返回 // reflect.Ptr; Get 出来的子值则存字段值。这个标记只为对齐 Raw() 的行为, // 不参与路径遍历。(放在 writable 后面, 落在原有的对齐填充里, rfx 仍是 24 字节) ptrRoot bool } // 编译期断言: 原型必须完整实现 R, 保证对外 API 签名不变。 var _ R = (*rfx)(nil) // invalid 表示"路径不存在", 全局共享一份, 命中不存在的路径时不产生分配。 var invalid = &rfx{} func (v *rfx) valid() bool { return v != nil && v.td != nil && v.ptr != nil } // --------------------------------------------------------------------------- // 路径遍历 // // 遍历过程中的中间状态全部用**值传递**的 rfx(24 字节, 完全落在栈上), // 只有最终要返回给调用方的那一个才装箱到堆上。这样一次 Get 无论路径多长 // 都只有 1 次分配 —— 而这 1 次是 R 链式 API 形状决定的下限。 // --------------------------------------------------------------------------- // normalize 把当前值解引用到"实际类型": 穿过指针链, 拆开 interface。 // 与 reflux 的 derefWithAccessor 对应, 同样支持解开 valuex.Accessor。 func (v rfx) normalize() (rfx, bool) { for { if v.td == nil || v.ptr == nil { return rfx{}, false } switch v.td.Kind { case reflect.Ptr: p := loadPtr(v.ptr) if p == nil { return rfx{}, false } v.ptr = p v.td = v.td.Elem case reflect.Interface: // interface 没有固定布局可以做偏移量运算, 退回 reflect 拆包 rv := valueAt(v.td, v.ptr) if rv.IsNil() { return rfx{}, false } // 支持 interface 里装着 valuex.Accessor / R 的情况 if acc, ok := rv.Interface().(valuex.Accessor); ok { raw := acc.Raw() if !raw.IsValid() { return rfx{}, false } return fromReflect(raw, v.writable) } return fromReflect(rv.Elem(), v.writable) default: return v, true } } } // fromReflect 把一个 reflect.Value 转换成 rfx 表示。 // 不可寻址的值会被拷贝到堆上(boxCopy), 并标记为不可写 —— 与 reflect 里 // "map 元素、interface 拆包结果不可寻址" 的语义一致。 func fromReflect(rv reflect.Value, writable bool) (rfx, bool) { if !rv.IsValid() { return rfx{}, false } switch { case rv.Kind() == reflect.Ptr: if rv.IsNil() { return rfx{}, false } return rfx{ td: rfxDescriptorOf(rv.Type().Elem()), ptr: rv.UnsafePointer(), writable: writable, }.normalize() case rv.CanAddr(): return rfx{ td: rfxDescriptorOf(rv.Type()), ptr: addrOf(rv), writable: writable && rv.CanSet(), }.normalize() default: return rfx{ td: rfxDescriptorOf(rv.Type()), ptr: boxCopy(rv), writable: false, }.normalize() } } // step 沿路径前进一段。 func (v rfx) step(seg string) (rfx, bool) { cur, ok := v.normalize() if !ok { return rfx{}, false } switch cur.td.Kind { case reflect.Struct: fd := cur.td.lookupField(seg) if fd == nil { return rfx{}, false } // I3: 未导出字段一律拒绝。reflect.NewAt 出来的 rfx 不带只读标记, // 放行会让调用方绕过 Go 的导出规则直接读写私有字段。 if !fd.Exported { return rfx{}, false } return rfx{ td: fd.Type, ptr: fieldAt(cur.ptr, fd.Offset), writable: cur.writable, }, true case reflect.Slice: idx, ok := parseIndex(seg) if !ok { return rfx{}, false } p := sliceElemAt(cur.ptr, idx, cur.td.elemSize) if p == nil { return rfx{}, false } // 切片元素落在底层数组里, 本身总是可寻址的 —— 与 reflect 的 // rfx.Index(i).CanSet() == true 保持一致。 return rfx{td: cur.td.Elem, ptr: p, writable: true}, true case reflect.Array: idx, ok := parseIndex(seg) if !ok { return rfx{}, false } p := arrayElemAt(cur.ptr, idx, cur.td.arrayLen, cur.td.elemSize) if p == nil { return rfx{}, false } return rfx{td: cur.td.Elem, ptr: p, writable: cur.writable}, true case reflect.Map: // map 没有稳定布局, 退回 reflect m := valueAt(cur.td, cur.ptr) if m.IsNil() { return rfx{}, false } mv := tryMapFieldValue(m, seg) if !mv.IsValid() { return rfx{}, false } return fromReflect(mv, false) default: return rfx{}, false } } // walk 沿整条路径前进, 全程不分配。 func (v rfx) walk(it pathIter) (rfx, bool) { cur := v for { seg, more := it.next() if !more { break } var ok bool cur, ok = cur.step(seg) if !ok { return rfx{}, false } } return cur.normalize() } // boxed 把栈上的遍历结果装箱成返回给调用方的 *rfx(唯一一次分配)。 func boxed(v rfx, ok bool) R { if !ok { return invalid } out := v return &out } // --------------------------------------------------------------------------- // R 接口: 热路径 // --------------------------------------------------------------------------- // Get 通过路径获取嵌套字段, struct 字段查找走 map。 func (v *rfx) Get(p ...string) R { if !v.valid() { return invalid } return boxed(v.walk(newPathIter(p))) } // 下面五个 xxxValue 是标量直取的**值接收者**辅助方法。 // // 它们存在的唯一理由是挡住逃逸: 如果直接在 getXxx 里写 (&cur).String(), // 局部变量 cur 就会逃逸到堆 —— Go 的逃逸分析是流不敏感的, 只要有一条路径 // 把 &cur 交出去, cur 在所有路径上都得堆分配, 快路径那 0 分配立刻退化成 1 次。 // 换成值接收者之后, 逃逸的是本方法的参数副本, 与调用方的 cur 无关。 func (v rfx) stringValue() string { if v.td != nil && v.ptr != nil && v.td.Kind == reflect.String { return loadString(v.ptr) } return (&v).String() } func (v rfx) intValue() int { if n, ok := v.scalarInt64(); ok { return int(n) } return (&v).Int() } func (v rfx) int64Value() int64 { if n, ok := v.scalarInt64(); ok { return n } return (&v).Int64() } func (v rfx) boolValue() bool { if v.td != nil && v.ptr != nil && v.td.Kind == reflect.Bool { return loadBool(v.ptr) } return (&v).Bool() } func (v rfx) float64Value() float64 { if f, ok := v.scalarFloat64(); ok { return f } return (&v).Float64() } // getString 等价于 Get(p...).String(), 但不产生中间的 R 包装对象。 func (v *rfx) getString(p ...string) string { if !v.valid() { return "" } cur, ok := v.walk(newPathIter(p)) if !ok { return "" } return cur.stringValue() } // getInt 等价于 Get(p...).Int(), 但不分配。 func (v *rfx) getInt(p ...string) int { if !v.valid() { return 0 } cur, ok := v.walk(newPathIter(p)) if !ok { return 0 } return cur.intValue() } // getInt64 等价于 Get(p...).Int64(), 但不分配。 func (v *rfx) getInt64(p ...string) int64 { if !v.valid() { return 0 } cur, ok := v.walk(newPathIter(p)) if !ok { return 0 } return cur.int64Value() } // getBool 等价于 Get(p...).Bool(), 但不分配。 func (v *rfx) getBool(p ...string) bool { if !v.valid() { return false } cur, ok := v.walk(newPathIter(p)) if !ok { return false } return cur.boolValue() } // getFloat64 等价于 Get(p...).Float64(), 但不分配。 func (v *rfx) getFloat64(p ...string) float64 { if !v.valid() { return 0 } cur, ok := v.walk(newPathIter(p)) if !ok { return 0 } return cur.float64Value() } func (v *rfx) Set(key string, val any) R { if !v.valid() { panic(NewErrInvalidValueForPath(key)) } parentIt, last, ok := splitLastStr(key) if !ok { panic(ErrEmptyPath) } parent, ok := v.walk(parentIt) if !ok || !parent.writable { // 两种情况交回 reflux 现有实现处理: // 1. 路径不存在 —— 让它给出与现状一致的错误信息 // 2. 父级不可写 —— 典型是路径穿过了 map: map 元素不可寻址, 取到的是 // 副本, 直接写副本不会反映到原 map 上。reflux 有完整的 // "取出-修改-写回 SetMapIndex" 逻辑, 复用它而不是重新实现一遍。 v.slow().Set(key, val) return v } if err := parent.setField(last, val); err != nil { panic(NewErrSetFailed(key, err)) } return v } // setField 在 parent 上设置名为 seg 的字段/键/下标。 func (v rfx) setField(seg string, val any) error { switch v.td.Kind { case reflect.Struct: fd := v.td.lookupField(seg) if fd == nil { return NewErrFieldNotFoundInStruct(seg, v.td.rtype) } // I3 + I4: 未导出字段、或整条访问链本身不可写, 都必须拒绝。 // reflect 路径上这两件事是 CanSet() 免费帮我们做的, unsafe 路径必须手写。 if !fd.Exported { return NewErrFieldCannotSet(seg, fd.Type.rtype) } if !v.writable { return NewErrFieldCannotSet(seg, fd.Type.rtype) } return v.assignField(fd.Type, fieldAt(v.ptr, fd.Offset), seg, val) case reflect.Slice: idx, ok := parseIndex(seg) if !ok { return NewErrInvalidSliceIndex(seg, fmt.Errorf("不是合法下标")) } if idx == -1 { // reflux 用 -1 表示前插, 要重新分配底层数组, 交给它处理 return v.slowSetField(seg, val) } p := sliceElemAt(v.ptr, idx, v.td.elemSize) if p == nil { // 与 reflux 一致: 越界是错误, 不会自动扩容。 // 这里直接构造错误而不是委托, 否则错误信息会被包装两层。 return NewErrSliceIndexOutOfRange(idx, sliceLen(v.ptr)) } return v.assignField(v.td.Elem, p, seg, val) case reflect.Array: idx, ok := parseIndex(seg) if !ok { return NewErrInvalidArrayIndex(seg, fmt.Errorf("不是合法下标")) } p := arrayElemAt(v.ptr, idx, v.td.arrayLen, v.td.elemSize) if p == nil { return NewErrArrayIndexOutOfRange(idx, v.td.arrayLen) } if !v.writable { return NewErrArrayElementCannotSet(idx) } return v.assignField(v.td.Elem, p, seg, val) case reflect.Map: return v.slowSetField(seg, val) default: return NewErrUnsupportedTargetType(v.td.Kind) } } // slowSetField 把设置操作交回 reflux 现有实现, 保证语义完全一致。 func (v rfx) slowSetField(seg string, val any) (err error) { defer func() { if r := recover(); r != nil { if e, ok := r.(error); ok { err = stripSetFailed(e) } else { err = fmt.Errorf("%v", r) } } }() if !v.writable { return NewErrCannotSetPath(seg) } v.slow().Set(seg, val) return nil } // stripSetFailed 剥掉 reflux 自己加的一层 ErrSetFailed 包装。 // // reflux 的 Set 失败时 panic 的是 NewErrSetFailed(seg, inner), 我们 recover 之后 // 外层还会再包一次完整路径, 不剥就会得到 // "set failed at path 'Items.10': set failed at path '10': index out of range" // 这种双层信息, 与现状不一致。 func stripSetFailed(err error) error { type multi interface{ Unwrap() []error } if m, ok := err.(multi); ok { parts := m.Unwrap() if len(parts) == 2 && errors.Is(parts[0], ErrSetFailed) { return parts[1] } } return err } // assignField 是所有字段赋值的统一入口, 按"能多快就多快, 但语义必须与 reflux 一致" // 的原则分三级: // // 1. 类型完全一致的常见标量 -> 直接按 *T 写内存, 零分配 // 2. 其它标量目标 -> 用 cast 转换(由 conv_equiv_test 全矩阵对拍保证一致) // 3. 复合目标(指针/切片/结构体/map/interface) -> **交回 reflux** // // 第 3 级不能自己实现: reflux 的 setValue 对这些类型有一整套语义 —— // 指针字段是"设置指针指向的值"而不是替换指针、[]any 会逐元素转成目标切片类型、 // map 可以填充进 struct。重新实现一遍必然出现行为偏差 // (ExampleNew_withPointer 就是这么发现的)。 func (v rfx) assignField(td *rfxTypeDesc, p unsafe.Pointer, seg string, val any) error { if storeFast(td, p, val) { return nil } // 类型完全匹配: 直接赋值, 不必绕道 if val != nil { if rv := reflect.ValueOf(val); rv.IsValid() && rv.Type() == td.rtype { valueAt(td, p).Set(rv) return nil } } if td.isScalar() { return assignReflect(valueAt(td, p), val) } return v.slowSetField(seg, val) } // storeFast 在"字段类型与传入值类型完全一致"时直接按类型写内存, 零分配、零转换。 // 返回 false 表示走不了快路径, 需要回退。 func storeFast(td *rfxTypeDesc, p unsafe.Pointer, val any) bool { switch td.fast { case fkString: if s, ok := val.(string); ok { storeString(p, s) return true } case fkInt: if i, ok := val.(int); ok { storeInt(p, i) return true } case fkBool: if b, ok := val.(bool); ok { storeBool(p, b) return true } case fkFloat64: if f, ok := val.(float64); ok { storeFloat64(p, f) return true } } return false } // assignReflect 是通用赋值回退路径, 与 reflux setValue 的转换策略一致: // 可直接赋值 -> 赋值; 可转换 -> 转换后赋值; 否则用 cast 做智能转换。 func assignReflect(dst reflect.Value, val any) error { if val == nil { dst.Set(reflect.Zero(dst.Type())) return nil } // 解开 valuex.Accessor / R if acc, ok := val.(valuex.Accessor); ok { if raw := acc.Raw(); raw.IsValid() { val = raw.Interface() } else { dst.Set(reflect.Zero(dst.Type())) return nil } } rv := reflect.ValueOf(val) dt := dst.Type() if rv.Type().AssignableTo(dt) { dst.Set(rv) return nil } switch dt.Kind() { case reflect.String: s, err := cast.ToStringE(val) if err != nil { return NewErrCannotAssign(rv.Type(), dt) } dst.SetString(s) return nil case reflect.Bool: b, err := cast.ToBoolE(val) if err != nil { return NewErrCannotAssign(rv.Type(), dt) } dst.SetBool(b) return nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: i, err := cast.ToInt64E(val) if err != nil { return NewErrCannotAssign(rv.Type(), dt) } if dst.OverflowInt(i) { return NewErrCannotAssign(rv.Type(), dt) } dst.SetInt(i) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: u, err := cast.ToUint64E(val) if err != nil { return NewErrCannotAssign(rv.Type(), dt) } if dst.OverflowUint(u) { return NewErrCannotAssign(rv.Type(), dt) } dst.SetUint(u) return nil case reflect.Float32, reflect.Float64: f, err := cast.ToFloat64E(val) if err != nil { return NewErrCannotAssign(rv.Type(), dt) } dst.SetFloat(f) return nil } if rv.Type().ConvertibleTo(dt) { dst.Set(rv.Convert(dt)) return nil } return NewErrCannotAssign(rv.Type(), dt) } // Exists 检查路径是否存在。 func (v *rfx) Exists(p ...string) bool { if !v.valid() { return false } if len(p) == 0 { // 必须规范化: 值可能是空指针, 或是装着 Nil 的 interface, // 这些情况下 Exists() 应该为 false。 _, ok := (*v).normalize() return ok } _, ok := v.walk(newPathIter(p)) return ok } // --------------------------------------------------------------------------- // R 接口: 冷路径 —— 直接委托给 reflux 现有实现, 保证行为完全一致 // --------------------------------------------------------------------------- // slow 把当前值交给基于 reflect 的冷路径实现 refx。 // 传的是 *T 指针, 所以不会发生深拷贝, 写操作落在同一块内存上。 func (v rfx) slow() R { if v.td == nil || v.ptr == nil { return Nil } // 直接构造 refx: 手上已经是一个合法的 *T 指针, 不需要再走一遍 // New 的类型校验和可能的深拷贝。 return &refx{value: ptrValueAt(v.td, v.ptr)} } func (v *rfx) Scope(p ...string) R { target := v.Get(p...) tv, ok := target.(*rfx) if !ok || !tv.valid() { return Nil } return tv.slow().Scope() } func (v *rfx) Append(items ...any) R { v.slow().Append(items...) return v } func (v *rfx) Delete(p ...string) R { v.slow().Delete(p...) return v } func (v *rfx) Array() []R { if !v.valid() { return nil } switch v.td.Kind { case reflect.Slice: n := sliceLen(v.ptr) // 批量分配: 一次开出 n 个 rfx 的连续内存, 再取每个元素的地址, // 把 n+1 次堆分配压成 2 次。元素游标本来就同生共死, 连续存放也更缓存友好。 buf := make([]rfx, n) out := make([]R, n) for i := 0; i < n; i++ { buf[i] = rfx{ td: v.td.Elem, ptr: sliceElemAt(v.ptr, i, v.td.elemSize), writable: true, } out[i] = &buf[i] } return out case reflect.Array: n := v.td.arrayLen out := make([]R, n) for i := 0; i < n; i++ { out[i] = &rfx{ td: v.td.Elem, ptr: arrayElemAt(v.ptr, i, n, v.td.elemSize), writable: v.writable, } } return out } return nil } func (v *rfx) Keys() []string { if !v.valid() { return nil } cur, ok := (*v).normalize() if !ok { return nil } switch cur.td.Kind { case reflect.Struct: out := make([]string, len(cur.td.fields)) for i := range cur.td.fields { out[i] = cur.td.fields[i].Name } return out case reflect.Map: // 不必判 IsNil: MapKeys() 对 nil map 返回空切片而不是 panic, // 于是这里得到 []string{} —— 与旧实现一致。提前返回 nil 会让 // DeepEqual 和 JSON 序列化(`[]` vs `null`)出现差异。 m := valueAt(cur.td, cur.ptr) keys := m.MapKeys() out := make([]string, len(keys)) // 字符串键直接取, 不必绕 fmt.Sprint —— 后者要先把 key 装箱成 // interface 再走一遍格式化, 实测 3 个键就差一倍。 // 非字符串键仍旧交给 fmt.Sprint: k.String() 对非字符串 Value 返回的是 // "" 这种占位串, 不是键本身。 if m.Type().Key().Kind() == reflect.String { for i, k := range keys { out[i] = k.String() } } else { for i, k := range keys { out[i] = fmt.Sprint(k.Interface()) } } return out } return v.slow().Keys() } func (v *rfx) MarshalJSON() ([]byte, error) { if !v.valid() { return []byte("null"), nil } return json.Marshal(valueAt(v.td, v.ptr).Interface()) } func (v *rfx) UnmarshalJSON(data []byte) error { if !v.valid() { return ErrInvalidValue } if !v.writable { return NewErrCannotSetPath("") } return json.Unmarshal(data, ptrValueAt(v.td, v.ptr).Interface()) } func (v *rfx) Lookup(path string) (valuex.Accessor, bool) { got := v.Get(path) if got.Exists() { return got, true } return valuex.Nil, false } func (v *rfx) MustLookup(path string) valuex.Accessor { got := v.Get(path) if got.Exists() { return got } return valuex.Nil } // --------------------------------------------------------------------------- // valuex.Accessor: 类型转换 // --------------------------------------------------------------------------- func (v *rfx) Raw() reflect.Value { if !v.valid() { return reflect.Value{} } if v.ptrRoot { // 与 reflux 对齐: New(&x) 的 Raw() 返回指针本身 return ptrValueAt(v.td, v.ptr) } return valueAt(v.td, v.ptr) } func (v *rfx) Ptr() any { if !v.valid() { return nil } return ptrValueAt(v.td, v.ptr).Interface() } func (v *rfx) Any() any { if !v.valid() { return nil } cur, ok := (*v).normalize() if !ok { return nil } return valueAt(cur.td, cur.ptr).Interface() } // --------------------------------------------------------------------------- // 标量直读快路径 // // 目标类型与字段类型"内存宽度一致"时, 直接按 *T 读内存, 不经过 // Any() -> interface 装箱 -> cast.ToXxxE 这条链路, 零分配。 // // 语义必须与 reflux(即 spf13/cast)完全一致, 已实测确认: // - 整数溢出是**静默截断**, 不报错 (cast.ToInt8E(300) == 44, nil) // - 负数转无符号才报错 (cast.ToUint8E(-1) -> error) // 因此整数之间用 Go 原生转换即可对齐; 负数转无符号一律回退到 cast, 保证 panic 信息一致。 // // 浮点字段读成窄整数(Int8/Int16/Int32)不走快路径 —— Go 里超范围的 float->int // 转换结果是实现定义的, 与 cast 的直接转换未必一致, 这种边角情况交给 cast。 // --------------------------------------------------------------------------- // scalarInt64 把整数/bool 类型的字段直接读成 int64。 // ok 为 false 表示当前类型没有快路径, 调用方需要回退到 cast。 func (v rfx) scalarInt64() (int64, bool) { switch v.td.Kind { case reflect.Int: return int64(loadInt(v.ptr)), true case reflect.Int8: return int64(loadInt8(v.ptr)), true case reflect.Int16: return int64(loadInt16(v.ptr)), true case reflect.Int32: return int64(loadInt32(v.ptr)), true case reflect.Int64: return loadInt64(v.ptr), true case reflect.Uint: return int64(loadUint(v.ptr)), true case reflect.Uint8: return int64(loadUint8(v.ptr)), true case reflect.Uint16: return int64(loadUint16(v.ptr)), true case reflect.Uint32: return int64(loadUint32(v.ptr)), true case reflect.Bool: if loadBool(v.ptr) { return 1, true } return 0, true } return 0, false } // scalarUint64 把整数/bool 类型的字段直接读成 uint64。 // 负数一律返回 ok=false 回退到 cast, 这样 panic 信息与 reflux 完全一致。 func (v rfx) scalarUint64() (uint64, bool) { switch v.td.Kind { case reflect.Uint: return uint64(loadUint(v.ptr)), true case reflect.Uint8: return uint64(loadUint8(v.ptr)), true case reflect.Uint16: return uint64(loadUint16(v.ptr)), true case reflect.Uint32: return uint64(loadUint32(v.ptr)), true case reflect.Uint64: return loadUint64(v.ptr), true // 注意: 这里**故意不处理** reflect.Uintptr。 // spf13/cast 不支持 uintptr, reflux 读 uintptr 字段是 panic 的; // 快路径若把它算进来就会返回数值, 与现状不一致。 // 由 TestFullInterfaceContract 的 "uintptr 字段读 Uint64" 用例钉住。 case reflect.Bool: if loadBool(v.ptr) { return 1, true } return 0, true } if n, ok := v.scalarInt64(); ok && n >= 0 { return uint64(n), true } return 0, false } // scalarFloat64 把数值类型的字段直接读成 float64。 func (v rfx) scalarFloat64() (float64, bool) { switch v.td.Kind { case reflect.Float64: return loadFloat64(v.ptr), true case reflect.Float32: return float64(loadFloat32(v.ptr)), true case reflect.Uint64: return float64(loadUint64(v.ptr)), true } if n, ok := v.scalarInt64(); ok { return float64(n), true } return 0, false } // isFloatKind 报告字段本身是不是浮点类型。 func (v rfx) isFloatKind() bool { return v.td.Kind == reflect.Float32 || v.td.Kind == reflect.Float64 } // String 对 string 类型有零分配快路径: 直接按 *string 读, 不经过 // interface 装箱和 cast。其余类型与 reflux 行为一致。 func (v *rfx) String() string { if v.valid() { // 数字/布尔转字符串也走直读 + strconv, 绕开 interface 装箱。 // 格式必须与 cast.ToStringE 完全一致, 由 TestScalarFastPathMatchesReflux // 的全矩阵对拍保证。 switch v.td.Kind { case reflect.String: return loadString(v.ptr) case reflect.Bool: return strconv.FormatBool(loadBool(v.ptr)) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: n, _ := (*v).scalarInt64() return strconv.FormatInt(n, 10) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: u, _ := (*v).scalarUint64() return strconv.FormatUint(u, 10) case reflect.Float64: return strconv.FormatFloat(loadFloat64(v.ptr), 'f', -1, 64) case reflect.Float32: return strconv.FormatFloat(float64(loadFloat32(v.ptr)), 'f', -1, 32) } } data := v.Any() if data == nil { return "" } result, err := cast.ToStringE(data) if err != nil { if b, e := json.Marshal(data); e == nil { return string(b) } panic(fmt.Sprintf("rfx: failed to convert to string: %v", err)) } return result } func (v *rfx) Bool() bool { if v.valid() && v.td.Kind == reflect.Bool { return loadBool(v.ptr) } result, err := cast.ToBoolE(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to bool: %v", err)) } return result } func (v *rfx) Int() int { if v.valid() { if n, ok := (*v).scalarInt64(); ok { return int(n) } } result, err := cast.ToIntE(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to int: %v", err)) } return result } func (v *rfx) Int64() int64 { if v.valid() { if n, ok := (*v).scalarInt64(); ok { return n } } result, err := cast.ToInt64E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to int64: %v", err)) } return result } // Int32/Int16/Int8 只在源本身是整数/bool 时走快路径。 // 浮点源交给 cast —— 超范围的 float->窄整数 转换在 Go 里是实现定义的。 func (v *rfx) Int32() int32 { if v.valid() && !v.isFloatKind() { if n, ok := (*v).scalarInt64(); ok { return int32(n) } } result, err := cast.ToInt32E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to int32: %v", err)) } return result } func (v *rfx) Int16() int16 { if v.valid() && !v.isFloatKind() { if n, ok := (*v).scalarInt64(); ok { return int16(n) } } result, err := cast.ToInt16E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to int16: %v", err)) } return result } func (v *rfx) Int8() int8 { if v.valid() && !v.isFloatKind() { if n, ok := (*v).scalarInt64(); ok { return int8(n) } } result, err := cast.ToInt8E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to int8: %v", err)) } return result } func (v *rfx) Uint() uint { if v.valid() { if n, ok := (*v).scalarUint64(); ok { return uint(n) } } result, err := cast.ToUintE(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to uint: %v", err)) } return result } func (v *rfx) Uint64() uint64 { if v.valid() { if n, ok := (*v).scalarUint64(); ok { return n } } result, err := cast.ToUint64E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to uint64: %v", err)) } return result } func (v *rfx) Uint32() uint32 { if v.valid() && !v.isFloatKind() { if n, ok := (*v).scalarUint64(); ok { return uint32(n) } } result, err := cast.ToUint32E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to uint32: %v", err)) } return result } func (v *rfx) Uint16() uint16 { if v.valid() && !v.isFloatKind() { if n, ok := (*v).scalarUint64(); ok { return uint16(n) } } result, err := cast.ToUint16E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to uint16: %v", err)) } return result } func (v *rfx) Uint8() uint8 { if v.valid() && !v.isFloatKind() { if n, ok := (*v).scalarUint64(); ok { return uint8(n) } } result, err := cast.ToUint8E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to uint8: %v", err)) } return result } func (v *rfx) Float64() float64 { if v.valid() { if f, ok := (*v).scalarFloat64(); ok { return f } } result, err := cast.ToFloat64E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to float64: %v", err)) } return result } func (v *rfx) Float32() float32 { if v.valid() { if f, ok := (*v).scalarFloat64(); ok { return float32(f) } } result, err := cast.ToFloat32E(v.Any()) if err != nil { panic(fmt.Sprintf("rfx: failed to convert to float32: %v", err)) } return result } func (v *rfx) StringMapString() map[string]string { return v.slow().StringMapString() } func (v *rfx) StringMapStringSlice() map[string][]string { return v.slow().StringMapStringSlice() } func (v *rfx) StringMapBool() map[string]bool { return v.slow().StringMapBool() } func (v *rfx) StringMapInt() map[string]int { return v.slow().StringMapInt() } func (v *rfx) StringMapInt64() map[string]int64 { return v.slow().StringMapInt64() } func (v *rfx) StringMap() map[string]any { return v.slow().StringMap() } func (v *rfx) Slice() []any { return v.slow().Slice() } func (v *rfx) BoolSlice() []bool { return v.slow().BoolSlice() } func (v *rfx) StringSlice() []string { return v.slow().StringSlice() } func (v *rfx) IntSlice() []int { return v.slow().IntSlice() }