fix: 补齐 Get[T] 的类型分支,避免静默返回零值

Get[T] 原本只处理 string/int/int64/bool/float64 五种,其余类型掉进 default
分支的 Any().(T) 断言。而断言**不做转换**,导致:

  Get[int32](r, "Age")            // 字段是 int(42) -> 静默返回 0
  Get[[]string](r, "Tags")        // 字段是 []any   -> 静默返回 nil
  Get[map[string]string](r, "M")  // 字段是 map[string]any -> 静默返回 nil

而对应的访问器 r.Get("Age").Int32() 等返回的是正确的转换结果。
实测 8 个场景里 7 个静默给错数据 —— 不报错不 panic,是最难排查的一类问题。

补齐后 T 覆盖 valuex.Accessor 全部转换方法对应的类型(9 个标量 + 4 种切片
+ 6 种 map),每个分支都落到同名访问器上,转换语义完全一致。
五种快路径类型的零分配特性不受影响(新分支同样用 detachPath 切断逃逸)。

新增 TestGenericMirrorsAccessors: 23 个用例逐个比对 Get[T] 与同名访问器,
并额外断言结果不是零值,防止将来有人删掉分支又掉回 default。
This commit is contained in:
2026-08-28 16:50:43 +08:00
parent a6283ac432
commit 9cb3ea857e
3 changed files with 187 additions and 12 deletions
+24 -4
View File
@@ -1099,14 +1099,34 @@ r.Get("Address", "City").String() // 2 次分配
reflux.Get[string](r, "Address", "City") // 0 次分配, 快约 1.7 倍
```
**覆盖类型**: `string` / `int` / `int64` / `bool` / `float64` 走零分配快路径;
其余类型走通用路径,行为等同 `r.Get(path...).Any().(T)`
**覆盖类型**: `T` 支持 `valuex.Accessor` 全部转换方法对应的类型,每个分支都落到
同名访问器上,因此**转换语义完全一致**:
| 类别 | 支持的 T |
|---|---|
| 零分配快路径 | `string` `int` `int64` `bool` `float64` |
| 其余标量 | `int8` `int16` `int32` `uint` `uint8` `uint16` `uint32` `uint64` `float32` |
| 切片 | `[]any` `[]string` `[]int` `[]bool` |
| map | `map[string]any` `map[string]string` `map[string]int` `map[string]int64` `map[string]bool` `map[string][]string` |
因为落到访问器上,所以**会做转换**而不是类型断言:
```go
type Doc struct{ Tags []any; Age int }
d := &Doc{Tags: []any{"a", "b"}, Age: 42}
r := reflux.New(d)
reflux.Get[[]string](r, "Tags") // ["a" "b"] —— 逐元素转换, 不是断言失败返回 nil
reflux.Get[int32](r, "Age") // 42 —— 与 r.Get("Age").Int32() 一致
```
**两点注意**:
1. `T` 只出现在返回值里,Go 无法类型推导,必须显式写出 `Get[string](...)`
2. 快路径只认原生标量类型。`Get[MyStr](r, "Name")` 在字段是原生 `string` 时,
会走通用路径并因类型断言失败返回零值 —— 这种场景请用 `r.Get("Name").String()`
2. **表格之外的类型**走 `Any().(T)` 断言,**不做转换** —— 这对
`Get[SomeStruct](r, "Field")` 这种"取出原样的值"是有用的,但具名标量类型
(`type MyStr string`)在字段是原生 `string` 时会断言失败返回零值,
这种场景请改用 `r.Get("Name").String()`
### Reflux 接口