- 如果目标字段是指针类型,它会尝试直接赋值(如果类型兼容),或创建一个新指针并递归设置其指向的值。 - `rfx_example_test.go` 中新增了测试用例,以验证对 `*string` 等指针字段的设置功能。
530 lines
13 KiB
Go
530 lines
13 KiB
Go
package reflux
|
|
|
|
import "fmt"
|
|
|
|
// ExampleNew_withPointer 演示如何使用 New 函数传入指针
|
|
// 传入指针时,修改会影响原始数据
|
|
func ExampleNew_withPointer() {
|
|
type Person struct {
|
|
Name string
|
|
Age int
|
|
Email *string
|
|
}
|
|
|
|
email := "alice@example.com"
|
|
person := Person{Name: "Alice", Age: 30, Email: &email}
|
|
|
|
// 传入指针 - 修改会影响原始数据
|
|
rfx := New(&person)
|
|
rfx.Set("Name", "Bob")
|
|
rfx.Set("Age", 35)
|
|
|
|
// 对于指针字段,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, Email: bob@example.com
|
|
}
|
|
|
|
// ExampleNew_withPointer_map 演示传入 map 指针
|
|
func ExampleNew_withPointer_map() {
|
|
config := map[string]any{
|
|
"host": "localhost",
|
|
"port": 8080,
|
|
}
|
|
|
|
// 传入 map 指针 - 修改会影响原始数据
|
|
rfx := New(&config)
|
|
rfx.Set("host", "127.0.0.1")
|
|
rfx.Set("port", 9090)
|
|
|
|
// 原始 map 已被修改
|
|
fmt.Printf("Host: %s, Port: %v\n", config["host"], config["port"])
|
|
|
|
// Output:
|
|
// Host: 127.0.0.1, Port: 9090
|
|
}
|
|
|
|
// ExampleNew_withPointer_slice 演示传入 slice 指针
|
|
func ExampleNew_withPointer_slice() {
|
|
items := []string{"apple", "banana", "cherry"}
|
|
|
|
// 传入 slice 指针 - 修改会影响原始数据
|
|
rfx := New(&items)
|
|
rfx.Set("0", "orange")
|
|
rfx.Set("2", "grape")
|
|
|
|
// 原始 slice 已被修改
|
|
fmt.Printf("Items: %v\n", items)
|
|
|
|
// Output:
|
|
// Items: [orange banana grape]
|
|
}
|
|
|
|
// ExampleNew_withValue 演示如何使用 New 函数传入值
|
|
// 传入值时,会创建深度克隆,修改不会影响原始数据
|
|
func ExampleNew_withValue() {
|
|
type Person struct {
|
|
Name string
|
|
Age int
|
|
Email *string
|
|
}
|
|
|
|
email := "alice@example.com"
|
|
person := Person{Name: "Alice", Age: 30, Email: &email}
|
|
|
|
// 传入值 - 会创建深度克隆,修改不会影响原始数据(包括指针字段)
|
|
rfx := New(person)
|
|
|
|
// 显示克隆后的数据(指针字段会显示实际值)
|
|
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, Email: %s\n", person.Name, person.Age, *person.Email)
|
|
|
|
// rfx 内部的数据已修改
|
|
fmt.Printf("Clone - Name: %s, Age: %d\n",
|
|
rfx.Get("Name").String(),
|
|
rfx.Get("Age").Int())
|
|
|
|
// Output:
|
|
// 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": &host,
|
|
"port": &port,
|
|
"enabled": true,
|
|
}
|
|
|
|
// 传入 map 值 - 会创建深度克隆(包括指针值)
|
|
rfx := New(config)
|
|
|
|
// 显示克隆后的数据(指针值会显示实际内容)
|
|
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: %d, Enabled: %t\n",
|
|
*config["host"].(*string),
|
|
*config["port"].(*int),
|
|
config["enabled"].(bool))
|
|
|
|
// 克隆的数据已修改
|
|
fmt.Printf("Clone - Host: %s, Port: %d, Enabled: %t\n",
|
|
*clonedConfig["host"].(*string),
|
|
*clonedConfig["port"].(*int),
|
|
clonedConfig["enabled"].(bool))
|
|
|
|
// Output:
|
|
// 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 值
|
|
// 传入值时会创建深度克隆,即使 slice 是引用类型
|
|
func ExampleNew_withValue_slice() {
|
|
items := []string{"apple", "banana", "cherry"}
|
|
|
|
// 传入 slice 值 - 会创建深度克隆
|
|
rfx := New(items)
|
|
fmt.Printf("After New: %v\n", rfx.Any())
|
|
|
|
rfx.Set("0", "orange")
|
|
rfx.Set("2", "grape")
|
|
|
|
// 原始 slice 未被修改
|
|
fmt.Printf("Original: %v\n", items)
|
|
|
|
// rfx 内部的数据已修改
|
|
fmt.Printf("Clone: [%s %s %s]\n",
|
|
rfx.Get("0").String(),
|
|
rfx.Get("1").String(),
|
|
rfx.Get("2").String())
|
|
|
|
// Output:
|
|
// After New: [apple banana cherry]
|
|
// Original: [apple banana cherry]
|
|
// Clone: [orange banana grape]
|
|
}
|
|
|
|
// ExampleNew_withValue_nestedStruct 演示传入嵌套结构体值
|
|
func ExampleNew_withValue_nestedStruct() {
|
|
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 := New(person)
|
|
fmt.Printf("After New: %+v\n", rfx.Any())
|
|
|
|
rfx.Set("Name", "Bob")
|
|
rfx.Set("Address.City", "Shanghai")
|
|
|
|
// 原始数据未被修改
|
|
fmt.Printf("Original - Name: %s, City: %s\n", person.Name, person.Address.City)
|
|
|
|
// rfx 内部的数据已修改
|
|
fmt.Printf("Clone - Name: %s, City: %s\n",
|
|
rfx.Get("Name").String(),
|
|
rfx.Get("Address", "City").String())
|
|
|
|
// Output:
|
|
// After New: {Name:Alice Address:{City:Beijing Street:Main St}}
|
|
// Original - Name: Alice, City: Beijing
|
|
// Clone - Name: Bob, City: Shanghai
|
|
}
|
|
|
|
// ExampleNew_withInterface 演示 interface{} 类型的支持
|
|
// 当数据被包装在 interface{} 中时,会自动解析到实际类型
|
|
func ExampleNew_withInterface() {
|
|
// interface{} 包装的 map
|
|
var config any = map[string]any{
|
|
"host": "localhost",
|
|
"port": 8080,
|
|
}
|
|
|
|
// 传入 interface{} 值 - 会创建深度克隆
|
|
rfx := New(config)
|
|
rfx.Set("host", "127.0.0.1")
|
|
rfx.Set("port", 9090)
|
|
|
|
// 原始数据未被修改
|
|
originalMap := config.(map[string]any)
|
|
fmt.Printf("Original - Host: %s, Port: %v\n", originalMap["host"], originalMap["port"])
|
|
|
|
// rfx 内部的数据已修改
|
|
fmt.Printf("Clone - Host: %s, Port: %v\n",
|
|
rfx.Get("host").String(),
|
|
rfx.Get("port").Int())
|
|
|
|
// Output:
|
|
// Original - Host: localhost, Port: 8080
|
|
// Clone - Host: 127.0.0.1, Port: 9090
|
|
}
|
|
|
|
// ExampleNew_withInterfacePointer 演示 interface{} 包装指针的情况
|
|
func ExampleNew_withInterfacePointer() {
|
|
type Config struct {
|
|
Host string
|
|
Port int
|
|
}
|
|
|
|
config := Config{Host: "localhost", Port: 8080}
|
|
|
|
// interface{} 包装指针 - 修改会影响原始数据
|
|
var data any = &config
|
|
rfx := New(data)
|
|
rfx.Set("Host", "127.0.0.1")
|
|
rfx.Set("Port", 9090)
|
|
|
|
// 原始数据已被修改(因为是指针)
|
|
fmt.Printf("Host: %s, Port: %d\n", config.Host, config.Port)
|
|
|
|
// Output:
|
|
// Host: 127.0.0.1, Port: 9090
|
|
}
|
|
|
|
// ExampleNew_withMap 演示如何使用 New 函数传入 map
|
|
func ExampleNew_withMap() {
|
|
// 创建一个 map
|
|
config := map[string]any{
|
|
"host": "localhost",
|
|
"port": 8080,
|
|
"ssl": true,
|
|
}
|
|
|
|
// 使用 New 创建 StructMap (必须传入指针)
|
|
rfx := New(&config)
|
|
|
|
// 获取值
|
|
host := rfx.Get("host").String()
|
|
port := rfx.Get("port").Int()
|
|
ssl := rfx.Get("ssl").Bool()
|
|
|
|
fmt.Printf("Host: %s\n", host)
|
|
fmt.Printf("Port: %d\n", port)
|
|
fmt.Printf("SSL: %t\n", ssl)
|
|
|
|
// 修改值
|
|
rfx.Set("host", "127.0.0.1")
|
|
rfx.Set("port", 9090)
|
|
|
|
// 添加新键
|
|
rfx.Set("timeout", 30)
|
|
|
|
fmt.Printf("Updated host: %s\n", config["host"])
|
|
fmt.Printf("Updated port: %v\n", config["port"])
|
|
fmt.Printf("New timeout: %v\n", config["timeout"])
|
|
|
|
// Output:
|
|
// Host: localhost
|
|
// Port: 8080
|
|
// SSL: true
|
|
// Updated host: 127.0.0.1
|
|
// Updated port: 9090
|
|
// New timeout: 30
|
|
}
|
|
|
|
// ExampleStructMap_Scope_noArgs 演示如何使用 Scope() 不传参数来复制整个对象
|
|
func ExampleStructMap_Scope_noArgs() {
|
|
type Config struct {
|
|
Host string
|
|
Port int
|
|
}
|
|
|
|
cfg := Config{
|
|
Host: "localhost",
|
|
Port: 8080,
|
|
}
|
|
|
|
rfx := New(&cfg)
|
|
|
|
// Scope 不传参数,创建整个对象的深度克隆
|
|
clone := rfx.Scope()
|
|
|
|
// 在克隆上修改值
|
|
clone.Set("Host", "127.0.0.1")
|
|
clone.Set("Port", 9090)
|
|
|
|
// 原对象不受影响
|
|
fmt.Printf("Original - Host: %s, Port: %d\n", cfg.Host, cfg.Port)
|
|
|
|
// 克隆对象已修改
|
|
fmt.Printf("Clone - Host: %s, Port: %d\n",
|
|
clone.Get("Host").String(),
|
|
clone.Get("Port").Int())
|
|
|
|
// Output:
|
|
// Original - Host: localhost, Port: 8080
|
|
// Clone - Host: 127.0.0.1, Port: 9090
|
|
}
|
|
|
|
// ExampleStructMap_Scope_withPath 演示如何使用 Scope() 传入路径来复制嵌套对象
|
|
func ExampleStructMap_Scope_withPath() {
|
|
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 := New(&person)
|
|
|
|
// 创建 Address 字段的 Scope (深度克隆)
|
|
addressScope := rfx.Scope("Address")
|
|
|
|
// 在 Scope 上修改值
|
|
addressScope.Set("City", "Shanghai")
|
|
addressScope.Set("Street", "New St")
|
|
|
|
// 原对象不受影响
|
|
fmt.Printf("Original Address - City: %s, Street: %s\n",
|
|
person.Address.City, person.Address.Street)
|
|
|
|
// Scope 对象已修改
|
|
fmt.Printf("Scope Address - City: %s, Street: %s\n",
|
|
addressScope.Get("City").String(),
|
|
addressScope.Get("Street").String())
|
|
|
|
// Output:
|
|
// Original Address - City: Beijing, Street: Main St
|
|
// Scope Address - City: Shanghai, Street: New St
|
|
}
|
|
|
|
// ExampleNew_withNestedMap 演示如何使用嵌套的 map
|
|
func ExampleNew_withNestedMap() {
|
|
data := map[string]any{
|
|
"user": map[string]any{
|
|
"name": "Alice",
|
|
"age": 30,
|
|
},
|
|
"tags": []string{"developer", "gopher"},
|
|
}
|
|
|
|
rfx := New(&data)
|
|
|
|
// 获取嵌套的值
|
|
userName := rfx.Get("user", "name").String()
|
|
userAge := rfx.Get("user", "age").Int()
|
|
firstTag := rfx.Get("tags", "0").String()
|
|
|
|
fmt.Printf("User: %s, Age: %d\n", userName, userAge)
|
|
fmt.Printf("First tag: %s\n", firstTag)
|
|
|
|
// 使用点号语法访问嵌套值
|
|
userName2 := rfx.Get("user.name").String()
|
|
fmt.Printf("User (dot notation): %s\n", userName2)
|
|
|
|
// Output:
|
|
// User: Alice, Age: 30
|
|
// First tag: developer
|
|
// User (dot notation): Alice
|
|
}
|
|
|
|
// ExampleStructMap_lowercaseFields 演示如何使用小写字段名访问 struct
|
|
func ExampleStructMap_lowercaseFields() {
|
|
type Person struct {
|
|
Name string
|
|
Age int
|
|
}
|
|
|
|
person := Person{
|
|
Name: "Alice",
|
|
Age: 30,
|
|
}
|
|
|
|
rfx := New(&person)
|
|
|
|
// 使用小写字段名获取值(自动转换为大写)
|
|
name := rfx.Get("name").String()
|
|
age := rfx.Get("age").Int()
|
|
|
|
fmt.Printf("Name: %s, Age: %d\n", name, age)
|
|
|
|
// 使用小写字段名设置值
|
|
rfx.Set("name", "Bob")
|
|
rfx.Set("age", 35)
|
|
|
|
fmt.Printf("Updated - Name: %s, Age: %d\n", person.Name, person.Age)
|
|
|
|
// Output:
|
|
// Name: Alice, Age: 30
|
|
// Updated - Name: Bob, Age: 35
|
|
}
|
|
|
|
// ExampleStructMap_lowercaseNestedFields 演示如何使用小写字段名访问嵌套 struct
|
|
func ExampleStructMap_lowercaseNestedFields() {
|
|
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 := New(&person)
|
|
|
|
// 使用小写字段名访问嵌套字段
|
|
city := rfx.Get("address", "city").String()
|
|
street := rfx.Get("address.street").String()
|
|
|
|
fmt.Printf("City: %s, Street: %s\n", city, street)
|
|
|
|
// 使用小写字段名设置嵌套字段
|
|
rfx.Set("address.city", "Shanghai")
|
|
rfx.Set("address.street", "New Street")
|
|
|
|
fmt.Printf("Updated City: %s, Street: %s\n",
|
|
person.Address.City, person.Address.Street)
|
|
|
|
// Output:
|
|
// City: Beijing, Street: Main St
|
|
// Updated City: Shanghai, Street: New Street
|
|
}
|
|
|
|
// ExampleStructMap_castConversion 演示使用 cast 进行智能类型转换
|
|
func ExampleStructMap_castConversion() {
|
|
type Config struct {
|
|
Port int
|
|
Host string
|
|
Enabled bool
|
|
Timeout float64
|
|
}
|
|
|
|
config := Config{}
|
|
rfx := New(&config)
|
|
|
|
// 字符串转数字
|
|
rfx.Set("Port", "8080")
|
|
fmt.Printf("Port (string->int): %d\n", config.Port)
|
|
|
|
// 数字转字符串
|
|
rfx.Set("Host", 12345)
|
|
fmt.Printf("Host (int->string): %s\n", config.Host)
|
|
|
|
// 字符串转布尔
|
|
rfx.Set("Enabled", "true")
|
|
fmt.Printf("Enabled (string->bool): %t\n", config.Enabled)
|
|
|
|
// 字符串转浮点数
|
|
rfx.Set("Timeout", "30.5")
|
|
fmt.Printf("Timeout (string->float): %.1f\n", config.Timeout)
|
|
|
|
// 链式调用不同类型转换
|
|
rfx.Set("Port", "9090").
|
|
Set("Host", "localhost").
|
|
Set("Enabled", "1").
|
|
Set("Timeout", "60")
|
|
|
|
fmt.Printf("\nAfter chain: Port=%d, Host=%s, Enabled=%t, Timeout=%.0f\n",
|
|
config.Port, config.Host, config.Enabled, config.Timeout)
|
|
|
|
// Output:
|
|
// Port (string->int): 8080
|
|
// Host (int->string): 12345
|
|
// Enabled (string->bool): true
|
|
// Timeout (string->float): 30.5
|
|
//
|
|
// After chain: Port=9090, Host=localhost, Enabled=true, Timeout=60
|
|
}
|