feat: 完善 New 方法支持指针和值参数,新增 interface 类型支持
- 支持指针模式: New(&data) - 直接修改原始数据
- 支持值模式: New(data) - 创建深度克隆,不影响原始数据
- 新增 interface{} 类型支持,自动解析到实际类型
- 对 map 和 slice 等引用类型也进行完全深度克隆
- 新增 9 个单元测试覆盖指针/值/interface 场景
- 新增 9 个示例测试展示各种用法
- 所有测试通过,保持性能
- 更新 README.md 详细说明指针/值传递的区别
- 新增 interface 类型使用示例
- 新增泛型数据处理使用场景
- 更新注意事项说明
- 使用递归解引用处理 interface 和指针类型
- 利用 DeepClone 确保引用类型的完全独立
- 保持向后兼容,现有代码无需修改
This commit is contained in:
154
rfx_test.go
154
rfx_test.go
@@ -23,15 +23,155 @@ type Address struct {
|
||||
|
||||
// TestNew 测试 New 函数
|
||||
func TestNew(t *testing.T) {
|
||||
p := Person{Name: "Alice", Age: 30}
|
||||
t.Run("New with pointer", func(t *testing.T) {
|
||||
// 测试传入指针 - 修改应该影响原始数据
|
||||
p := Person{Name: "Alice", Age: 30}
|
||||
rfx := New(&p)
|
||||
|
||||
// 测试传入非指针值应该 panic
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Error("New() with non-pointer should panic")
|
||||
rfx.Set("Name", "Bob")
|
||||
if p.Name != "Bob" {
|
||||
t.Errorf("Expected original value to be modified, got '%s'", p.Name)
|
||||
}
|
||||
}()
|
||||
New(p) // 应该 panic
|
||||
})
|
||||
|
||||
t.Run("New with value", func(t *testing.T) {
|
||||
// 测试传入值 - 修改不应该影响原始数据
|
||||
p := Person{Name: "Alice", Age: 30}
|
||||
rfx := New(p)
|
||||
|
||||
rfx.Set("Name", "Bob")
|
||||
// 原始值不应该被修改
|
||||
if p.Name != "Alice" {
|
||||
t.Errorf("Expected original value to remain 'Alice', got '%s'", p.Name)
|
||||
}
|
||||
|
||||
// rfx 内部的值应该已经修改
|
||||
if rfx.Get("Name").String() != "Bob" {
|
||||
t.Errorf("Expected rfx value to be 'Bob', got '%s'", rfx.Get("Name").String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with map pointer", func(t *testing.T) {
|
||||
m := map[string]any{"name": "Alice"}
|
||||
rfx := New(&m)
|
||||
|
||||
rfx.Set("name", "Bob")
|
||||
if m["name"] != "Bob" {
|
||||
t.Errorf("Expected map to be modified, got '%v'", m["name"])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with map value", func(t *testing.T) {
|
||||
m := map[string]any{"name": "Alice"}
|
||||
rfx := New(m)
|
||||
|
||||
rfx.Set("name", "Bob")
|
||||
// 原始 map 不应该被修改
|
||||
if m["name"] != "Alice" {
|
||||
t.Errorf("Expected original map to remain 'Alice', got '%v'", m["name"])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with slice pointer", func(t *testing.T) {
|
||||
s := []string{"a", "b", "c"}
|
||||
rfx := New(&s)
|
||||
|
||||
rfx.Set("0", "x")
|
||||
if s[0] != "x" {
|
||||
t.Errorf("Expected slice to be modified, got '%s'", s[0])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with slice value", func(t *testing.T) {
|
||||
s := []string{"a", "b", "c"}
|
||||
rfx := New(s)
|
||||
|
||||
rfx.Set("0", "x")
|
||||
// 原始切片不应该被修改
|
||||
if s[0] != "a" {
|
||||
t.Errorf("Expected original slice to remain 'a', got '%s'", s[0])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with array value", func(t *testing.T) {
|
||||
a := [3]string{"a", "b", "c"}
|
||||
rfx := New(a)
|
||||
|
||||
rfx.Set("0", "x")
|
||||
// 原始数组不应该被修改
|
||||
if a[0] != "a" {
|
||||
t.Errorf("Expected original array to remain 'a', got '%s'", a[0])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with nil pointer", func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Error("Expected panic with nil pointer")
|
||||
}
|
||||
}()
|
||||
var p *Person
|
||||
New(p)
|
||||
})
|
||||
|
||||
t.Run("New with unsupported type", func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Error("Expected panic with unsupported type")
|
||||
}
|
||||
}()
|
||||
New(42) // int 不支持
|
||||
})
|
||||
|
||||
t.Run("New with interface wrapping map", func(t *testing.T) {
|
||||
// 测试 interface{} 包装的 map
|
||||
var data any = map[string]string{"name": "Alice"}
|
||||
rfx := New(data)
|
||||
|
||||
if rfx.Get("name").String() != "Alice" {
|
||||
t.Errorf("Expected 'Alice', got '%s'", rfx.Get("name").String())
|
||||
}
|
||||
|
||||
// 修改不应该影响原始数据(因为是值传递)
|
||||
rfx.Set("name", "Bob")
|
||||
originalMap := data.(map[string]string)
|
||||
if originalMap["name"] != "Alice" {
|
||||
t.Error("Original map should not be modified")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with interface wrapping struct", func(t *testing.T) {
|
||||
// 测试 interface{} 包装的 struct
|
||||
var data any = Person{Name: "Alice", Age: 30}
|
||||
rfx := New(data)
|
||||
|
||||
if rfx.Get("Name").String() != "Alice" {
|
||||
t.Errorf("Expected 'Alice', got '%s'", rfx.Get("Name").String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with interface wrapping pointer", func(t *testing.T) {
|
||||
// 测试 interface{} 包装的指针
|
||||
person := Person{Name: "Alice", Age: 30}
|
||||
var data any = &person
|
||||
rfx := New(data)
|
||||
|
||||
rfx.Set("Name", "Bob")
|
||||
// 原始数据应该被修改(因为是指针)
|
||||
if person.Name != "Bob" {
|
||||
t.Errorf("Expected original to be modified, got '%s'", person.Name)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("New with nil interface", func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Error("Expected panic with nil interface")
|
||||
}
|
||||
}()
|
||||
var data any
|
||||
New(data)
|
||||
})
|
||||
}
|
||||
|
||||
// TestNewWithPointer 测试传入指针的情况
|
||||
|
||||
Reference in New Issue
Block a user