Go to file
2025-12-09 20:06:56 +08:00
valuex feat: Accessor 支持 2025-12-08 17:25:44 +08:00
errors_example_test.go feat: 增强错误处理与示例 2025-12-09 20:06:56 +08:00
errors.go feat: 增强错误处理与示例 2025-12-09 20:06:56 +08:00
go.mod first commit 2025-12-02 19:52:29 +08:00
go.sum first commit 2025-12-02 19:52:29 +08:00
README.md feat: R 接口支持 JSON 序列化和反序列化 2025-12-08 17:22:05 +08:00
reflux.go feat: R 接口支持 JSON 序列化和反序列化 2025-12-08 17:22:05 +08:00
rfx_append_test.go feat: Append 方法支持 R 接口包装的指针类型 2025-12-08 17:24:45 +08:00
rfx_example_test.go feat: 增强类型转换能力和代码重构 2025-12-05 11:12:11 +08:00
rfx_json_test.go feat: R 接口支持 JSON 序列化和反序列化 2025-12-08 17:22:05 +08:00
rfx_map_case_test.go feat: 增强 map 大小写不敏感支持和函数重命名 2025-12-09 16:55:13 +08:00
rfx_nil_test.go feat: 增强 nil 值处理能力 2025-12-09 15:11:18 +08:00
rfx_test.go feat: Append 方法支持 R 接口包装的指针类型 2025-12-08 17:24:45 +08:00
rfx.go feat: 增强错误处理与示例 2025-12-09 20:06:56 +08:00
util.go feat: 增强错误处理与示例 2025-12-09 20:06:56 +08:00

Reflux

Reflux 是一个 Go 语言包,提供了统一的接口用于访问和操作嵌套的结构体字段、切片元素和映射值。通过字符串路径的方式,可以方便地访问和修改深层嵌套的数据结构。

特性

  • 🔍 统一访问: 使用字符串路径访问结构体、Map、切片中的任意嵌套值
  • 🎯 点号路径: 支持点号分割的路径语法,如 Get("Address.City")
  • 🔄 类型转换: 基于 spf13/cast 的强大类型转换支持
  • ✏️ 修改数据: 支持通过路径设置和删除值
  • 🔗 链式调用: Set 和 Delete 方法支持链式调用,如 rfx.Set("name", "Alice").Delete("age").Set("city", "Beijing")
  • 📋 深度克隆: Scope 方法和值传递模式创建深度克隆,修改不影响原始数据
  • 🎭 灵活模式: 支持指针和值两种传递方式,提供不同的数据操作语义
  • 🔌 Interface 支持: 自动解析 interface{} 类型到实际类型
  • 🔤 大小写不敏感: 支持使用小写字段名访问和修改结构体字段(包括 Map 键名)
  • 🔑 键名提取: Keys 方法可获取结构体或 Map 的所有键名
  • 📝 JSON 集成: Ptr() 方法返回的指针可直接用于 json.Unmarshal(),实现动态 JSON 反序列化
  • 🎯 JSON 序列化: 实现 json.Marshaler 和 json.Unmarshaler 接口,支持直接序列化和反序列化 R 实例
  • 🎯 类型安全: 使用反射但保证类型安全
  • 🔥 增强类型转换: 支持切片和结构体之间的智能转换(如 []any -> []T, map -> struct)
  • 🌀 R 接口集成: 支持直接传入 R 接口或 []R 切片,无缝集成反射值
  • 🚀 高性能: 优化的反射操作,低内存开销
  • 📦 零依赖: 仅依赖 Go 标准库和 spf13/cast

安装

go get git.fsdpf.net/go/reflux

快速开始

package main

import (
    "fmt"
    "git.fsdpf.net/go/reflux"
)

type User struct {
    Name    string
    Age     int
    Address struct {
        City string
    }
}

func main() {
    user := User{
        Name: "Alice",
        Age:  30,
    }
    user.Address.City = "Beijing"

    rfx := reflux.New(&user)

    // 获取值
    name := rfx.Get("Name").String()
    age := rfx.Get("Age").Int()
    city := rfx.Get("Address", "City").String()

    fmt.Printf("Name: %s, Age: %d, City: %s\n", name, age, city)

    // 链式设置值
    rfx.Set("Name", "Bob").Set("Age", 35).Set("Address.City", "Shanghai")

    fmt.Printf("Updated: %+v\n", user)
}

核心功能

1. 创建 Reflux

Reflux 支持指针两种传递方式,提供不同的数据操作语义:

指针模式 - 直接修改原始数据

user := User{Name: "Alice"}
rfx := reflux.New(&user)  // 传入指针

rfx.Set("Name", "Bob")
// user.Name 已被修改为 "Bob"

值模式 - 深度克隆,不影响原始数据

user := User{Name: "Alice"}
rfx := reflux.New(user)  // 传入值

rfx.Set("Name", "Bob")
// user.Name 仍然是 "Alice"
// rfx 内部是独立的深度克隆

Interface 类型支持

Reflux 支持 interface{} (或 any) 类型,会自动解析到实际类型:

// interface{} 包装的值 - 创建深度克隆
var config any = map[string]string{"host": "localhost"}
rfx := reflux.New(config)
rfx.Set("host", "127.0.0.1")
// 原始 config 不受影响

// interface{} 包装的指针 - 直接修改
var data any = &config
rfx := reflux.New(data)
rfx.Set("host", "127.0.0.1")
// config 已被修改

支持的类型

类型 说明 示例
Struct 结构体 New(Person{})New(&person)
Map 映射 New(map[string]any{})New(&m)
Slice 切片 New([]string{})New(&s)
Array 数组 New([3]int{})New(&a)
Interface 接口 New(anyValue) - 自动解析

重要说明:

  • 指针模式: 传入指针(如 &user)时,所有修改都会直接影响原始数据
  • 值模式: 传入值(如 user)时,会创建深度克隆,修改不影响原始数据
  • 深度克隆: 对于 map 和 slice 等引用类型,值模式也会创建完全独立的副本
  • 不支持: 基本类型(int, string, bool)、chan、func 等不是容器的类型

2. 获取值 (Get)

// 获取顶层字段
name := rfx.Get("Name").String()

// 获取嵌套字段 - 使用多个参数
city := rfx.Get("Address", "City").String()

// 获取嵌套字段 - 使用点号路径
city := rfx.Get("Address.City").String()

// 深层嵌套 - 点号路径
ceoCity := rfx.Get("Company.CEO.Address.City").String()

// 混合使用点号和参数
value := rfx.Get("User.Profile", "Settings", "Theme").String()

// 获取切片元素 - 使用索引
tag := rfx.Get("Tags", "0").String()

// 获取切片元素 - 使用点号
tag := rfx.Get("Tags.0").String()

// 获取 Map 值 - 使用多个参数
value := rfx.Get("Meta", "key").String()

// 获取 Map 值 - 使用点号
value := rfx.Get("Meta.key").String()

// 大小写不敏感访问 - 结构体字段和 Map 键名
name := rfx.Get("name").String()  // 等同于 Get("Name")
city := rfx.Get("address.city").String()  // 等同于 Get("Address.City")

// Map 类型也支持大小写转换
config := map[string]string{"Host": "localhost"}
rfx := reflux.New(&config)
host := rfx.Get("host").String()  // 自动尝试 "Host"

3. 作用域 (Scope)

Scope 方法创建指定路径的深度克隆,在克隆上的修改不会影响原始数据:

type Address struct {
    City   string
    Street string
}

type Person struct {
    Name    string
    Address Address
}

person := Person{
    Name: "Alice",
    Address: Address{
        City:   "Beijing",
        Street: "Main St",
    },
}

rfx := reflux.New(&person)

// 创建 Address 字段的深度克隆
addressScope := rfx.Scope("Address")

// 在克隆上修改值
addressScope.Set("City", "Shanghai")
addressScope.Set("Street", "New St")

// 原始数据不受影响
fmt.Println(person.Address.City)    // 输出: Beijing
fmt.Println(person.Address.Street)  // 输出: Main St

// 克隆数据已修改
fmt.Println(addressScope.Get("City").String())    // 输出: Shanghai
fmt.Println(addressScope.Get("Street").String())  // 输出: New St

// 不传参数时,克隆整个对象
clone := rfx.Scope()
clone.Set("Name", "Bob")
fmt.Println(person.Name)  // 输出: Alice (原始数据不变)

重要: Scope 返回的是深度克隆,与原始数据完全独立。

4. 设置值 (Set)

Set 方法使用新的 API 签名: Set(key string, v any) Reflux,支持链式调用:

// 链式设置多个值
rfx.Set("Name", "Bob").Set("Age", 35).Set("Address.City", "Shanghai")

// 设置顶层字段
rfx.Set("Name", "Bob")

// 设置嵌套字段 - 使用点号路径
rfx.Set("Address.City", "Shanghai")

// 深层嵌套设置
rfx.Set("Company.CEO.Address.City", "Guangzhou")

// 设置 Map 值
rfx.Set("Meta.key", "value")

// 设置切片元素
rfx.Set("Tags.0", "newValue")

// 大小写不敏感设置
rfx.Set("name", "Bob")  // 等同于 Set("Name", "Bob")
rfx.Set("address.city", "Shanghai")  // 等同于 Set("Address.City", "Shanghai")

// 自动类型转换
rfx.Set("Age", int32(35))  // int32 -> int

// 切片类型转换 - 从通用切片转为具体类型
rfx.Set("Scores", []any{90, 95, 88})  // []any -> []int

// 结构体类型转换 - 从 map 填充到 struct
addressMap := map[string]any{
    "City":   "Shanghai",
    "Street": "Nanjing Road",
}
rfx.Set("Address", addressMap)  // map -> Address struct

// 指针切片赋值 - 保持指针引用
type Item struct {
    Name string
}
item1 := &Item{Name: "apple"}
item2 := &Item{Name: "banana"}
rfx.Set("Items", []*Item{item1, item2})  // 保持原指针地址

// 也支持从 []any 包含指针元素
rfx.Set("Items", []any{item1, item2})  // 复用指针地址

// R 接口和 []R 切片支持
rfx1 := reflux.New(data1)
rfx2 := reflux.New(data2)
rfx.Set("Item", rfx1)           // 直接传入 R 接口
rfx.Set("Items", []R{rfx1, rfx2})  // 传入 R 切片

// Map 自动初始化
rfx.Set("NewMap.key", "value")  // 如果 NewMap 是 nil,会自动初始化

注意: 如果设置失败(路径不存在、类型不匹配等),会 panic。

高级类型转换

Reflux 提供了强大的智能类型转换能力,支持多种复杂场景:

1. 切片类型转换

支持从通用切片(如 []any)转换为具体类型切片:

type Person struct {
    Scores []int
    Tags   []string
}

p := Person{}
rfx := reflux.New(&p)

// []any -> []int
rfx.Set("Scores", []any{90, 95, 88})
// p.Scores = []int{90, 95, 88}

// []any -> []string (自动类型转换)
rfx.Set("Tags", []any{"go", "rust", 123})
// p.Tags = []string{"go", "rust", "123"}

2. 结构体类型转换

支持从 map 或其他结构体填充到目标结构体:

type Address struct {
    City   string
    Street string
}

type Person struct {
    Address Address
}

p := Person{}
rfx := reflux.New(&p)

// map -> struct
addressMap := map[string]any{
    "City":   "Shanghai",
    "Street": "Nanjing Road",
}
rfx.Set("Address", addressMap)
// p.Address = Address{City: "Shanghai", Street: "Nanjing Road"}

// struct -> struct (按字段名匹配)
src := Address{City: "Beijing", Street: "Changan"}
rfx.Set("Address", src)

3. 指针切片处理

对于包含指针的切片,Reflux 会保持指针引用:

type Fruit struct {
    Name string
}

type Basket struct {
    Fruits []*Fruit
}

basket := Basket{}
rfx := reflux.New(&basket)

apple := &Fruit{Name: "apple"}
banana := &Fruit{Name: "banana"}

// 保持指针引用,不创建新对象
rfx.Set("Fruits", []*Fruit{apple, banana})

// 修改原指针对象,basket.Fruits 中会看到相同变化
apple.Name = "green apple"
// basket.Fruits[0].Name == "green apple"

// 也支持从 []any 赋值,复用指针地址
rfx.Set("Fruits", []any{apple, banana})

4. R 接口集成

支持直接传入 R 接口或 []R 切片:

// 传入单个 R 接口
data1 := map[string]string{"key": "value"}
rfx1 := reflux.New(data1)
rfx.Set("Item", rfx1)  // 自动提取底层值

// 传入 []R 切片
data2 := map[string]int{"count": 10}
rfx2 := reflux.New(data2)
rfx.Set("Items", []R{rfx1, rfx2})  // 自动转换为底层切片

5. reflect.Value 支持

可以直接传入 reflect.Value,避免重复封装:

import "reflect"

val := reflect.ValueOf(someData)
rfx.Set("Field", val)  // 直接使用,不重复包装

这些高级转换特性使得 Reflux 在处理复杂数据结构和动态类型场景时更加灵活和强大。

切片追加 (Append)

Append 用于在当前 R 对应的切片上追加一个或多个元素,并支持自动类型转换:

// 追加到顶层切片
items := []string{"apple", "banana"}
rfx := reflux.New(&items)

// 追加单个和多个元素
rfx.Append("cherry")
rfx.Append("durian", "kiwi")
// items == []string{"apple", "banana", "cherry", "durian", "kiwi"}

// 使用索引 -1 在切片前面插入新元素
// 相当于在开头插入,原有元素整体后移
rfx.Set("-1", "first")
// 对于上面的 items,现在结果为:
// items == []string{"first", "apple", "banana", "cherry", "durian", "kiwi"}

// 追加时支持类型转换
nums := []int{1, 2}
rfxNums := reflux.New(&nums)
rfxNums.Append("3", 4.0) // "3" -> 3, 4.0 -> 4
// nums == []int{1, 2, 3, 4}

// 追加到嵌套切片字段
type Container struct {
    Tags []string
}
c := Container{Tags: []string{"go"}}
rfxContainer := reflux.New(&c)
rfxContainer.Get("Tags").Append("rust", "python")
// c.Tags == []string{"go", "rust", "python"}

注意:

  • 只能对切片类型调用 Append,否则会 panic
  • 追加多个值时会一次性追加,避免多次扩容

5. 删除值 (Delete)

Delete 方法支持链式调用,返回 Reflux 自身:

// 删除 Map 键 - 使用多个参数
rfx.Delete("Meta", "key")

// 删除 Map 键 - 使用点号
rfx.Delete("Meta.key")

// 删除切片元素 - 使用索引
rfx.Delete("Tags", "1")  // 删除索引 1 的元素

// 删除切片元素 - 使用点号
rfx.Delete("Tags.1")

// 链式调用 - 删除多个值
rfx.Delete("Meta.key1").Delete("Meta.key2").Set("Meta.key3", "value")

注意: 如果删除失败(路径不存在、类型不支持删除等),会 panic。

6. 检查存在性 (Exists)

if rfx.Exists("Name") {
    fmt.Println("Name field exists")
}

// 使用多个参数检查嵌套字段
if rfx.Exists("Address", "City") {
    fmt.Println("Nested field exists")
}

// 使用点号路径检查嵌套字段
if rfx.Exists("Address.City") {
    fmt.Println("Nested field exists")
}

// 检查深层嵌套
if rfx.Exists("Company.CEO.Address.City") {
    fmt.Println("Deep nested field exists")
}

7. 获取键名 (Keys)

type User struct {
    Name string
    Age  int
}

user := User{Name: "Alice", Age: 30}
rfx := reflux.New(&user)

// 获取结构体的所有字段名
keys := rfx.Keys()
fmt.Println(keys)  // 输出: [Name Age]

// 对于 Map
config := map[string]any{
    "host": "localhost",
    "port": 8080,
}
sm2 := reflux.New(&config)
keys2 := sm2.Keys()
fmt.Println(keys2)  // 输出: [host port]

// 获取嵌套对象的键名
addressKeys := rfx.Get("Address").Keys()

8. 数组操作 (Array)

// 将切片转换为 Reflux 数组
tags := rfx.Get("Tags").Array()
for i, tag := range tags {
    fmt.Printf("Tag[%d]: %s\n", i, tag.String())
}

// 可以对数组元素进行进一步操作
users := rfx.Get("Users").Array()
for i, user := range users {
    name := user.Get("Name").String()
    age := user.Get("Age").Int()
    fmt.Printf("User[%d]: %s, %d\n", i, name, age)
}

9. 类型转换

基本类型

age := rfx.Get("Age").Int()        // int
age64 := rfx.Get("Age").Int64()    // int64
age32 := rfx.Get("Age").Int32()    // int32
age16 := rfx.Get("Age").Int16()    // int16
age8 := rfx.Get("Age").Int8()      // int8
uage := rfx.Get("Age").Uint()      // uint
uage64 := rfx.Get("Age").Uint64()  // uint64
uage32 := rfx.Get("Age").Uint32()  // uint32
uage16 := rfx.Get("Age").Uint16()  // uint16
uage8 := rfx.Get("Age").Uint8()    // uint8
fage := rfx.Get("Age").Float64()   // float64
fage32 := rfx.Get("Age").Float32() // float32
sage := rfx.Get("Age").String()    // string
active := rfx.Get("Active").Bool() // bool

注意: 类型转换使用 spf13/cast 库,支持智能类型转换。转换失败会 panic。

Map 类型

// map[string]string
strMap := rfx.Get("Meta").StringMapString()

// map[string]int
intMap := rfx.Get("Scores").StringMapInt()

// map[string]int64
int64Map := rfx.Get("Scores").StringMapInt64()

// map[string]bool
boolMap := rfx.Get("Flags").StringMapBool()

// map[string]any
anyMap := rfx.Get("Data").StringMap()

// map[string][]string
sliceMap := rfx.Get("Tags").StringMapStringSlice()

切片类型

// []string
tags := rfx.Get("Tags").StringSlice()

// []int
scores := rfx.Get("Scores").IntSlice()

// []bool
flags := rfx.Get("Flags").BoolSlice()

// []any
items := rfx.Get("Items").Slice()

10. 底层访问

// 获取 reflect.Value
val := rfx.Get("Name").Value()

// 获取指针
ptr := rfx.Get("Name").Ptr()

// 获取 any 类型
any := rfx.Get("Name").Any()

与 json.Unmarshal() 配合使用

Ptr() 方法返回的指针可以直接用于 json.Unmarshal(),实现动态的 JSON 反序列化:

import (
    "encoding/json"
    "git.fsdpf.net/go/reflux"
)

type Person struct {
    Name    string
    Age     int
    Address Address
    Meta    map[string]string
    Tags    []string
}

type Address struct {
    City    string
    Street  string
    ZipCode int
}

func main() {
    p := Person{
        Name: "Alice",
        Address: Address{City: "OldCity"},
        Meta: make(map[string]string),
    }

    rfx := reflux.New(&p)

    // 1. 更新嵌套结构体
    addressJSON := []byte(`{
        "City": "Shanghai",
        "Street": "Nanjing Road",
        "ZipCode": 200000
    }`)
    json.Unmarshal(addressJSON, rfx.Get("Address").Ptr())
    // p.Address 已被完整更新

    // 2. 更新 Map 字段
    metaJSON := []byte(`{
        "key1": "value1",
        "key2": "value2"
    }`)
    json.Unmarshal(metaJSON, rfx.Get("Meta").Ptr())
    // p.Meta 已被填充

    // 3. 更新切片字段
    tagsJSON := []byte(`["go", "rust", "python"]`)
    json.Unmarshal(tagsJSON, rfx.Get("Tags").Ptr())
    // p.Tags 已被替换

    // 4. 更新整个对象
    personJSON := []byte(`{
        "Name": "Bob",
        "Age": 35
    }`)
    json.Unmarshal(personJSON, rfx.Ptr())
    // 整个 Person 对象被更新
}

使用场景:

  • 动态配置更新: 从 JSON 文件或 API 响应更新配置的特定部分
  • 部分数据刷新: 只更新对象的某个嵌套字段,其他字段保持不变
  • 插件系统: 动态加载和更新插件配置
  • 热更新: 在运行时更新应用配置而无需重启

11. JSON 序列化和反序列化

R 接口实现了 json.Marshalerjson.Unmarshaler 接口,支持直接对 R 实例进行 JSON 序列化和反序列化:

JSON 序列化 (MarshalJSON)

import (
    "encoding/json"
    "git.fsdpf.net/go/reflux"
)

type Person struct {
    Name string
    Age  int
    Tags []string
}

func main() {
    person := Person{
        Name: "Alice",
        Age:  30,
        Tags: []string{"developer", "golang"},
    }

    rfx := reflux.New(&person)

    // 直接序列化 R 实例
    data, err := json.Marshal(rfx)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(data))
    // 输出: {"Name":"Alice","Age":30,"Tags":["developer","golang"]}
}

JSON 反序列化 (UnmarshalJSON)

func main() {
    person := Person{}
    rfx := reflux.New(&person)

    jsonData := []byte(`{"Name":"Bob","Age":35,"Tags":["manager","python"]}`)

    // 直接反序列化到 R 实例
    err := json.Unmarshal(jsonData, rfx)
    if err != nil {
        panic(err)
    }

    // 数据已更新到原始对象
    fmt.Printf("%+v\n", person)
    // 输出: {Name:Bob Age:35 Tags:[manager python]}

    // 也可以通过 R 接口访问
    fmt.Println(rfx.Get("Name").String())  // 输出: Bob
    fmt.Println(rfx.Get("Age").Int())       // 输出: 35
}

JSON 往返转换

func main() {
    // 原始数据
    original := map[string]any{
        "name":   "Charlie",
        "age":    40,
        "active": true,
    }

    rfx1 := reflux.New(&original)

    // 序列化
    data, _ := json.Marshal(rfx1)

    // 反序列化到新对象
    result := make(map[string]any)
    rfx2 := reflux.New(&result)
    json.Unmarshal(data, rfx2)

    // 验证数据一致性
    fmt.Println(rfx2.Get("name").String())    // Charlie
    fmt.Println(rfx2.Get("age").Float64())    // 40 (JSON 数字默认 float64)
    fmt.Println(rfx2.Get("active").Bool())    // true
}

嵌套结构序列化

type Address struct {
    City    string
    Country string
}

type User struct {
    Name    string
    Age     int
    Address Address
}

func main() {
    user := User{
        Name: "David",
        Age:  45,
        Address: Address{
            City:    "Beijing",
            Country: "China",
        },
    }

    rfx := reflux.New(&user)

    // 序列化整个嵌套结构
    data, _ := json.Marshal(rfx)
    fmt.Println(string(data))
    // 输出: {"Name":"David","Age":45,"Address":{"City":"Beijing","Country":"China"}}

    // 只序列化某个嵌套字段
    addressData, _ := json.Marshal(rfx.Get("Address"))
    fmt.Println(string(addressData))
    // 输出: {"City":"Beijing","Country":"China"}
}

智能类型转换

反序列化时,R 接口会自动进行类型转换:

type Config struct {
    Port    int
    Timeout int64
    Enabled bool
}

func main() {
    config := Config{}
    rfx := reflux.New(&config)

    // JSON 中的数字默认是 float64
    jsonData := []byte(`{"Port":8080,"Timeout":30,"Enabled":true}`)
    json.Unmarshal(jsonData, rfx)

    // 自动转换为目标类型
    fmt.Printf("Port: %d (type: int)\n", config.Port)           // 8080
    fmt.Printf("Timeout: %d (type: int64)\n", config.Timeout)   // 30
    fmt.Printf("Enabled: %v (type: bool)\n", config.Enabled)    // true
}

使用场景:

  • API 通信: 直接序列化 R 实例发送到 HTTP API
  • 配置持久化: 将配置对象保存为 JSON 文件
  • 数据传输: 在不同系统间传输复杂数据结构
  • 缓存系统: 将对象序列化后存储到 Redis 等缓存
  • 消息队列: 序列化后通过消息队列传输

注意事项:

  • 序列化会调用底层 Any() 方法获取实际值
  • 反序列化支持智能类型转换,使用 setValue 方法
  • 对于 struct 类型,会按字段名匹配反序列化
  • JSON 数字默认解析为 float64,会自动转换为目标类型

使用场景

1. 配置文件处理

type Config struct {
    Database struct {
        Host string
        Port int
    }
    Redis struct {
        Addr string
    }
}

config := loadConfig()
rfx := reflux.New(&config)

// 动态读取配置
dbHost := rfx.Get("Database", "Host").String()
dbPort := rfx.Get("Database", "Port").Int()

// 链式修改配置
rfx.Set("Database.Host", "localhost").Set("Database.Port", 3306)

2. API 响应处理

response := map[string]any{
    "user": map[string]any{
        "name": "Alice",
        "age":  30,
    },
    "status": "success",
}

rfx := reflux.New(&response)
userName := rfx.Get("user", "name").String()
userAge := rfx.Get("user", "age").Int()

// 修改响应数据
rfx.Set("user.name", "Bob").Set("status", "updated")

3. 动态表单数据

formData := map[string]any{
    "name":  "Bob",
    "email": "bob@example.com",
    "age":   "25",  // 字符串形式的数字
}

rfx := reflux.New(&formData)

// 自动类型转换
name := rfx.Get("name").String()
age := rfx.Get("age").Int()  // "25" -> 25

// 验证和修改
if age < 18 {
    rfx.Set("verified", false)
}

4. 测试数据构建

testUser := User{}
rfx := reflux.New(&testUser)

// 链式快速设置测试数据
rfx.Set("Name", "TestUser").
   Set("Age", 25).
   Set("Address.City", "Beijing").
   Set("Address.Street", "Test St")

5. 数据克隆和隔离

original := Config{Host: "localhost"}
rfx := reflux.New(&original)

// 创建深度克隆进行测试
testConfig := rfx.Scope()
testConfig.Set("Host", "test-server").Set("Port", 9999)

// 原始配置不受影响
fmt.Println(original.Host)  // 输出: localhost

6. JSON 动态更新

使用 Ptr() 方法配合 json.Unmarshal() 实现动态更新:

type AppConfig struct {
    Server   ServerConfig
    Database DatabaseConfig
    Features map[string]bool
}

type ServerConfig struct {
    Host string
    Port int
}

type DatabaseConfig struct {
    Driver string
    DSN    string
}

func main() {
    config := AppConfig{
        Server: ServerConfig{
            Host: "localhost",
            Port: 8080,
        },
        Features: make(map[string]bool),
    }

    rfx := reflux.New(&config)

    // 从配置文件或 API 只更新 Server 配置
    serverJSON := []byte(`{
        "Host": "production.example.com",
        "Port": 443
    }`)
    json.Unmarshal(serverJSON, rfx.Get("Server").Ptr())

    // 动态启用功能开关
    featuresJSON := []byte(`{
        "newFeature": true,
        "experimentalUI": false
    }`)
    json.Unmarshal(featuresJSON, rfx.Get("Features").Ptr())

    // config.Server 已更新,config.Database 保持不变
    fmt.Printf("%+v\n", config)
}

这种方式特别适合:

  • 微服务配置: 从配置中心动态更新特定模块配置
  • A/B 测试: 实时更新功能开关
  • 插件热加载: 更新插件配置而无需重启
  • API 部分响应: 只处理 API 返回的部分字段

7. 泛型数据处理 (Interface 类型)

使用 interface{} 类型处理未知类型的数据:

// 函数返回 any 类型
func loadFromAPI() any {
    // 可能返回 map 或 struct
    return map[string]any{
        "user": map[string]any{
            "name": "Alice",
            "age":  30,
        },
    }
}

func processData(data any) {
    // 自动解析 interface{} 到实际类型
    rfx := reflux.New(data)  // 值模式,创建深度克隆

    // 安全地修改数据
    rfx.Set("user.name", "Bob")
    rfx.Set("user.age", 35)

    // 原始数据不受影响
}

// 或者使用指针模式
func updateData(dataPtr any) {
    // interface{} 包装指针,直接修改
    rfx := reflux.New(dataPtr)
    rfx.Set("user.name", "Charlie")
    // 原始数据已被修改
}

使用场景:

  • 插件系统: 处理未知结构的插件配置
  • 泛型配置: 统一处理不同格式的配置数据
  • API 适配: 适配多种 API 响应格式
  • 数据转换: 在不同数据结构间转换

路径语法

Reflux 支持灵活的点号路径语法:

// 以下调用是等价的:
rfx.Get("a.b.c")
rfx.Get("a.b", "c")
rfx.Get("a", "b.c")
rfx.Get("a", "b", "c")

// 空段会被忽略
rfx.Get("a..b")   // 等价于 rfx.Get("a", "b")
rfx.Get(".a.b.")  // 等价于 rfx.Get("a", "b")

// 点号路径适用于所有方法
rfx.Set("a.b.c", value)
rfx.Delete("a.b.c")
rfx.Exists("a.b.c")
rfx.Scope("a.b.c")

// 访问切片元素
tag := rfx.Get("Tags.0").String()

// 访问 Map 值
value := rfx.Get("Config.Database.Host").String()

API 文档

Reflux 接口

type Reflux interface {
    // 路径操作
    Get(p ...string) Reflux
    Scope(p ...string) Reflux

    // 修改操作 (支持链式调用)
    Set(key string, v any) Reflux
    Delete(p ...string) Reflux
    Exists(p ...string) bool

    // 数组和键操作
    Array() []Reflux
    Keys() []string

    // 底层访问
    Value() reflect.Value
    Ptr() any
    Any() any

    // 基本类型转换
    Bool() bool
    Int() int
    Int8() int8
    Int16() int16
    Int32() int32
    Int64() int64
    Uint() uint
    Uint8() uint8
    Uint16() uint16
    Uint32() uint32
    Uint64() uint64
    Float32() float32
    Float64() float64
    String() string

    // Map 类型转换
    StringMapString() map[string]string
    StringMapStringSlice() map[string][]string
    StringMapBool() map[string]bool
    StringMapInt() map[string]int
    StringMapInt64() map[string]int64
    StringMap() map[string]any

    // Slice 类型转换
    Slice() []any
    BoolSlice() []bool
    StringSlice() []string
    IntSlice() []int
}

注意事项

  1. 指针 vs 值传递:
    • 传入指针 (New(&data)) 时,修改会影响原始数据
    • 传入 (New(data)) 时,会创建深度克隆,修改不影响原始数据
    • 对于 map 和 slice 等引用类型,值模式也会完全克隆
  2. Interface 支持: 支持 interface{} 类型,会自动解析到实际类型并保持正确的指针/值语义
  3. Scope 行为: Scope 返回深度克隆,修改不会影响原始数据
  4. 链式调用: Set 和 Delete 方法都支持链式调用,返回 Reflux 自身
  5. 类型转换: 使用 spf13/cast 进行类型转换,转换失败会 panic
  6. 切片删除: 删除切片元素会创建新切片并重新赋值
  7. Map 初始化: 对 nil map 调用 Set 会自动初始化 map
  8. 大小写不敏感: 支持使用小写字段名访问结构体字段
  9. JSON 集成: Ptr() 返回的指针可以安全地用于 json.Unmarshal()
  10. 并发安全: Reflux 本身不是并发安全的,需要外部同步
  11. 错误处理: 大多数转换、设置和删除操作失败时会 panic,请确保路径和类型正确