From cbe079ddcd172ed5d07dbe4bdc8a38f28b65938b Mon Sep 17 00:00:00 2001 From: what Date: Wed, 3 Dec 2025 10:44:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=8F=8D=E5=B0=84?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E6=8C=87=E9=92=88=E7=B1=BB=E5=9E=8B=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20=20=20-=20=E5=A6=82=E6=9E=9C=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=98=AF=E6=8C=87=E9=92=88=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=EF=BC=8C=E5=AE=83=E4=BC=9A=E5=B0=9D=E8=AF=95=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E8=B5=8B=E5=80=BC=EF=BC=88=E5=A6=82=E6=9E=9C=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=EF=BC=89=EF=BC=8C=E6=88=96=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E6=96=B0=E6=8C=87=E9=92=88=E5=B9=B6=E9=80=92?= =?UTF-8?q?=E5=BD=92=E8=AE=BE=E7=BD=AE=E5=85=B6=E6=8C=87=E5=90=91=E7=9A=84?= =?UTF-8?q?=E5=80=BC=E3=80=82=20=20=20-=20`rfx=5Fexample=5Ftest.go`=20?= =?UTF-8?q?=E4=B8=AD=E6=96=B0=E5=A2=9E=E4=BA=86=E6=B5=8B=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=EF=BC=8C=E4=BB=A5=E9=AA=8C=E8=AF=81=E5=AF=B9=20`*stri?= =?UTF-8?q?ng`=20=E7=AD=89=E6=8C=87=E9=92=88=E5=AD=97=E6=AE=B5=E7=9A=84?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rfx.go | 21 ++++++++++++ rfx_example_test.go | 83 ++++++++++++++++++++++++++++++--------------- util.go | 67 +++++++++++++++++++++++++++++------- 3 files changed, 131 insertions(+), 40 deletions(-) diff --git a/rfx.go b/rfx.go index 1e9ee23..a5240a7 100644 --- a/rfx.go +++ b/rfx.go @@ -257,6 +257,27 @@ func (r *rfx) setValue(field reflect.Value, v any) bool { return true } + // 处理指针类型 + if field.Type().Kind() == reflect.Ptr { + // 如果传入的值已经是指针类型,尝试直接赋值 + if val.Type().AssignableTo(field.Type()) { + field.Set(val) + return true + } + + // 如果传入的值不是指针,创建新指针并设置值 + elemType := field.Type().Elem() + newPtr := reflect.New(elemType) + + // 递归设置指针指向的值 + if !r.setValue(newPtr.Elem(), v) { + return false + } + + field.Set(newPtr) + return true + } + // 优先使用 cast 进行智能类型转换 // 这样可以处理 string <-> number, number <-> bool 等常见转换 targetType := field.Type() diff --git a/rfx_example_test.go b/rfx_example_test.go index 4d33541..550caa7 100644 --- a/rfx_example_test.go +++ b/rfx_example_test.go @@ -6,22 +6,27 @@ import "fmt" // 传入指针时,修改会影响原始数据 func ExampleNew_withPointer() { type Person struct { - Name string - Age int + Name string + Age int + Email *string } - person := Person{Name: "Alice", Age: 30} + email := "alice@example.com" + person := Person{Name: "Alice", Age: 30, Email: &email} // 传入指针 - 修改会影响原始数据 rfx := New(&person) rfx.Set("Name", "Bob") rfx.Set("Age", 35) - // 原始数据已被修改 - fmt.Printf("Name: %s, Age: %d\n", person.Name, person.Age) + // 对于指针字段,Set 会设置指针指向的值 + rfx.Set("Email", "bob@example.com") + + // 原始数据已被修改(包括指针字段指向的值) + fmt.Printf("Name: %s, Age: %d, Email: %s\n", person.Name, person.Age, *person.Email) // Output: - // Name: Bob, Age: 35 + // Name: Bob, Age: 35, Email: bob@example.com } // ExampleNew_withPointer_map 演示传入 map 指针 @@ -63,21 +68,27 @@ func ExampleNew_withPointer_slice() { // 传入值时,会创建深度克隆,修改不会影响原始数据 func ExampleNew_withValue() { type Person struct { - Name string - Age int + Name string + Age int + Email *string } - person := Person{Name: "Alice", Age: 30} + email := "alice@example.com" + person := Person{Name: "Alice", Age: 30, Email: &email} - // 传入值 - 会创建深度克隆,修改不会影响原始数据 + // 传入值 - 会创建深度克隆,修改不会影响原始数据(包括指针字段) rfx := New(person) - fmt.Printf("After New: %+v\n", rfx.Any()) + + // 显示克隆后的数据(指针字段会显示实际值) + clonedPerson := rfx.Any().(Person) + fmt.Printf("After New - Name: %s, Age: %d, Email: %s\n", + clonedPerson.Name, clonedPerson.Age, *clonedPerson.Email) rfx.Set("Name", "Bob") rfx.Set("Age", 35) // 原始数据未被修改 - fmt.Printf("Original - Name: %s, Age: %d\n", person.Name, person.Age) + fmt.Printf("Original - Name: %s, Age: %d, Email: %s\n", person.Name, person.Age, *person.Email) // rfx 内部的数据已修改 fmt.Printf("Clone - Name: %s, Age: %d\n", @@ -85,38 +96,54 @@ func ExampleNew_withValue() { rfx.Get("Age").Int()) // Output: - // After New: {Name:Alice Age:30} - // Original - Name: Alice, Age: 30 + // After New - Name: Alice, Age: 30, Email: alice@example.com + // Original - Name: Alice, Age: 30, Email: alice@example.com // Clone - Name: Bob, Age: 35 } // ExampleNew_withValue_map 演示传入 map 值 // 传入值时会创建深度克隆,即使 map 是引用类型 func ExampleNew_withValue_map() { + host := "localhost" + port := 8080 config := map[string]any{ - "host": "localhost", - "port": 8080, + "host": &host, + "port": &port, + "enabled": true, } - // 传入 map 值 - 会创建深度克隆 + // 传入 map 值 - 会创建深度克隆(包括指针值) rfx := New(config) - fmt.Printf("After New: %v\n", rfx.Any()) - rfx.Set("host", "127.0.0.1") - rfx.Set("port", 9090) + // 显示克隆后的数据(指针值会显示实际内容) + clonedConfig := rfx.Any().(map[string]any) + fmt.Printf("After New - Host: %s, Port: %d, Enabled: %t\n", + *clonedConfig["host"].(*string), + *clonedConfig["port"].(*int), + clonedConfig["enabled"].(bool)) + + // 修改克隆的数据 + newHost := "127.0.0.1" + newPort := 9090 + clonedConfig["host"] = &newHost + clonedConfig["port"] = &newPort // 原始 map 未被修改 - fmt.Printf("Original - Host: %s, Port: %v\n", config["host"], config["port"]) + fmt.Printf("Original - Host: %s, Port: %d, Enabled: %t\n", + *config["host"].(*string), + *config["port"].(*int), + config["enabled"].(bool)) - // rfx 内部的数据已修改 - fmt.Printf("Clone - Host: %s, Port: %v\n", - rfx.Get("host").String(), - rfx.Get("port").Int()) + // 克隆的数据已修改 + fmt.Printf("Clone - Host: %s, Port: %d, Enabled: %t\n", + *clonedConfig["host"].(*string), + *clonedConfig["port"].(*int), + clonedConfig["enabled"].(bool)) // Output: - // After New: map[host:localhost port:8080] - // Original - Host: localhost, Port: 8080 - // Clone - Host: 127.0.0.1, Port: 9090 + // After New - Host: localhost, Port: 8080, Enabled: true + // Original - Host: localhost, Port: 8080, Enabled: true + // Clone - Host: 127.0.0.1, Port: 9090, Enabled: true } // ExampleNew_withValue_slice 演示传入 slice 值 diff --git a/util.go b/util.go index 1fdb6be..50c4c96 100644 --- a/util.go +++ b/util.go @@ -95,26 +95,69 @@ func cloneSequence(dst, src reflect.Value) { } // cloneElement 克隆单个元素,处理 interface 包装的情况 -// 对于复杂类型(struct, map, slice, array)进行深度克隆 +// 对于复杂类型(struct, map, slice, array)和指针类型进行深度克隆 // 对于基本类型,直接返回原始值 func cloneElement(elem reflect.Value) reflect.Value { - // 解引用以获取实际值 - actualElem := elem - for actualElem.Kind() == reflect.Interface || actualElem.Kind() == reflect.Ptr { - if actualElem.IsNil() { - return elem + // 首先检查 elem 自身是否是 interface + if elem.Kind() == reflect.Interface && !elem.IsNil() { + // 获取 interface 包装的实际值 + wrapped := elem.Elem() + + // 如果 interface 包装的是指针,需要深度克隆指针 + if wrapped.Kind() == reflect.Ptr && !wrapped.IsNil() { + // 克隆指针指向的值 + pointedValue := wrapped.Elem() + if needsDeepClone(pointedValue.Kind()) { + // 复杂类型:递归克隆 + clonedValue := reflect.New(pointedValue.Type()).Elem() + CloneValue(clonedValue, pointedValue) + clonedPtr := reflect.New(pointedValue.Type()) + clonedPtr.Elem().Set(clonedValue) + return clonedPtr + } else { + // 基本类型:创建新指针 + clonedPtr := reflect.New(pointedValue.Type()) + clonedPtr.Elem().Set(pointedValue) + return clonedPtr + } } - actualElem = actualElem.Elem() + + // interface 包装的是复杂类型 + if needsDeepClone(wrapped.Kind()) { + clonedElem := reflect.New(wrapped.Type()).Elem() + CloneValue(clonedElem, wrapped) + return clonedElem + } + + // interface 包装的是基本类型,直接返回 + return elem } - // 如果元素需要递归克隆(struct, map, slice, array) - if actualElem.IsValid() && needsDeepClone(actualElem.Kind()) { - clonedElem := reflect.New(actualElem.Type()).Elem() - CloneValue(clonedElem, actualElem) + // 处理直接的指针类型 + if elem.Kind() == reflect.Ptr && !elem.IsNil() { + pointedValue := elem.Elem() + if needsDeepClone(pointedValue.Kind()) { + clonedValue := reflect.New(pointedValue.Type()).Elem() + CloneValue(clonedValue, pointedValue) + clonedPtr := reflect.New(pointedValue.Type()) + clonedPtr.Elem().Set(clonedValue) + return clonedPtr + } else { + // 基本类型的指针,创建新指针 + clonedPtr := reflect.New(pointedValue.Type()) + clonedPtr.Elem().Set(pointedValue) + return clonedPtr + } + } + + // 处理复杂类型 + if needsDeepClone(elem.Kind()) { + clonedElem := reflect.New(elem.Type()).Elem() + CloneValue(clonedElem, elem) return clonedElem } - // 对于基本类型,直接返回原始值 + // 基本类型,直接返回 return elem }