diff --git a/example/benchmark/main.go b/example/benchmark/main.go index ae87c8b..4ad3c40 100644 --- a/example/benchmark/main.go +++ b/example/benchmark/main.go @@ -2,110 +2,216 @@ package main import ( "fmt" - "time" + "testing" "github.com/devfeel/mapper" ) -// Test structs with 10 fields -type Source struct { - Name string - Age int - Email string - Phone string - Address string - City string - Country string - ZipCode string - Status int - Score float64 +// 测试用结构体 +type ( + BenchUser struct { + ID int64 `mapper:"id"` + Name string `mapper:"name"` + Email string `mapper:"email"` + Age int `mapper:"age"` + CreatedAt int64 `mapper:"created_at"` + Score float64 + } + + BenchUserDTO struct { + ID int64 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Age int `json:"age"` + CreatedAt int64 `json:"created_at"` + Score float64 `json:"score"` + } +) + +// Benchmark_MapDirect_1000 benchmark for MapDirect with 1000 iterations +func Benchmark_MapDirect_1000(b *testing.B) { + user := BenchUser{ + ID: 1, + Name: "Test User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = mapper.MapDirect[BenchUser, BenchUserDTO](user) + } } -type Dest struct { - Name string - Age int - Email string - Phone string - Address string - City string - Country string - ZipCode string - Status int - Score float64 +// Benchmark_MapDirectSlice_10 benchmark for MapDirectSlice with 10 items +func Benchmark_MapDirectSlice_10(b *testing.B) { + users := make([]BenchUser, 10) + for i := 0; i < 10; i++ { + users[i] = BenchUser{ + ID: int64(i), + Name: "User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = mapper.MapDirectSlice[BenchUser, BenchUserDTO](users) + } } -func main() { - // Create test data - src := &Source{ - Name: "test", - Age: 25, - Email: "test@example.com", - Phone: "1234567890", - Address: "123 Test St", - City: "TestCity", - Country: "TestCountry", - ZipCode: "12345", - Status: 1, - Score: 95.5, - } - - // Test 1: Single mapping - fmt.Println("=== Test 1: Single Mapping ===") - start := time.Now() +// Benchmark_MapDirectSlice_100 benchmark for MapDirectSlice with 100 items +func Benchmark_MapDirectSlice_100(b *testing.B) { + users := make([]BenchUser, 100) + for i := 0; i < 100; i++ { + users[i] = BenchUser{ + ID: int64(i), + Name: "User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = mapper.MapDirectSlice[BenchUser, BenchUserDTO](users) + } +} + +// Benchmark_MapDirectSlice_1000 benchmark for MapDirectSlice with 1000 items +func Benchmark_MapDirectSlice_1000(b *testing.B) { + users := make([]BenchUser, 1000) for i := 0; i < 1000; i++ { - dest := &Dest{} - mapper.Mapper(src, dest) + users[i] = BenchUser{ + ID: int64(i), + Name: "User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = mapper.MapDirectSlice[BenchUser, BenchUserDTO](users) } - elapsed := time.Since(start) - fmt.Printf("1000 single mappings: %v\n", elapsed) - fmt.Printf("Average per mapping: %v\n", elapsed/time.Duration(1000)) +} - // Test 2: Slice mapping - fmt.Println("\n=== Test 2: Slice Mapping ===") - srcList := make([]Source, 100) +// Benchmark_MapDirectPtrSlice_100 benchmark for MapDirectPtrSlice with 100 items +func Benchmark_MapDirectPtrSlice_100(b *testing.B) { + users := make([]*BenchUser, 100) for i := 0; i < 100; i++ { - srcList[i] = Source{ - Name: "test", - Age: 25, - Email: "test@example.com", - Phone: "1234567890", - Address: "123 Test St", - City: "TestCity", - Country: "TestCountry", - ZipCode: "12345", - Status: 1, - Score: 95.5, + users[i] = &BenchUser{ + ID: int64(i), + Name: "User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, } } - start = time.Now() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = mapper.MapDirectPtrSlice[BenchUser, BenchUserDTO](users) + } +} + +// Benchmark_SafeMapDirect benchmark for SafeMapDirect +func Benchmark_SafeMapDirect(b *testing.B) { + user := BenchUser{ + ID: 1, + Name: "Test User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = mapper.SafeMapDirect[BenchUser, BenchUserDTO](user) + } +} + +// Benchmark_SafeMapDirectSlice_100 benchmark for SafeMapDirectSlice with 100 items +func Benchmark_SafeMapDirectSlice_100(b *testing.B) { + users := make([]BenchUser, 100) for i := 0; i < 100; i++ { - var destList []Dest - mapper.MapperSlice(srcList, &destList) + users[i] = BenchUser{ + ID: int64(i), + Name: "User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } } - elapsed = time.Since(start) - fmt.Printf("100 slice mappings (100 items each): %v\n", elapsed) - fmt.Printf("Average per slice: %v\n", elapsed/time.Duration(100)) - // Test 3: Different types - fmt.Println("\n=== Test 3: Different Type Pairs ===") - type TypeA struct{ Name string } - type TypeB struct{ Name string } - type TypeC struct{ Value int } - type TypeD struct{ Value int } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = mapper.SafeMapDirectSlice[BenchUser, BenchUserDTO](users) + } +} - start = time.Now() - for i := 0; i < 1000; i++ { - a := &TypeA{Name: "test"} - b := &TypeB{} - mapper.Mapper(a, b) +// Benchmark_Old_Mapper benchmark for traditional Mapper +func Benchmark_Old_Mapper(b *testing.B) { + user := &BenchUser{ + ID: 1, + Name: "Test User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } + userDTO := &BenchUserDTO{} - c := &TypeC{Value: 100} - d := &TypeD{} - mapper.Mapper(c, d) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = mapper.Mapper(user, userDTO) } - elapsed = time.Since(start) - fmt.Printf("1000 different type mappings: %v\n", elapsed) +} - fmt.Println("\n=== All tests completed ===") +// Benchmark_Old_MapperSlice benchmark for traditional MapperSlice +func Benchmark_Old_MapperSlice(b *testing.B) { + users := make([]BenchUser, 100) + for i := 0; i < 100; i++ { + users[i] = BenchUser{ + ID: int64(i), + Name: "User", + Email: "test@example.com", + Age: 25, + CreatedAt: 1704067200, + Score: 95.5, + } + } + userDTOs := &[]BenchUserDTO{} + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = mapper.MapperSlice(users, userDTOs) + } +} + +// 运行示例 +func main() { + fmt.Println("=== Mapper 性能测试示例 ===") + fmt.Println() + fmt.Println("运行基准测试:") + fmt.Println(" go test -bench=Benchmark -benchmem ./benchmark/") + fmt.Println() + fmt.Println("运行特定测试:") + fmt.Println(" go test -bench=MapDirectSlice_100 -benchmem ./benchmark/") + fmt.Println() + fmt.Println("示例输出:") + fmt.Println(" Benchmark_MapDirectSlice_100-8 20000 58000 ns/op") + fmt.Println(" 说明: 每次映射 100 条数据,耗时约 58 微秒") } diff --git a/example/config/main.go b/example/config/main.go new file mode 100644 index 0000000..8663fb8 --- /dev/null +++ b/example/config/main.go @@ -0,0 +1,197 @@ +package main + +import ( + "fmt" + + "github.com/devfeel/mapper" +) + +// 定义测试结构体 +type ( + Source struct { + ID int64 `mapper:"id" json:"id" form:"id"` + Name string `mapper:"name" json:"name" form:"name"` + Age int `mapper:"age" json:"age" form:"age"` + Email string `mapper:"email" json:"email" form:"email"` + Password string `mapper:"-" json:"-" form:"-"` + Private string `mapper:"private" json:"private" form:"private"` + } + + Target struct { + ID int64 `json:"id"` + Name string `json:"name"` + Age int `json:"age"` + Email string `json:"email"` + Password string `json:"-"` + Private string `json:"private"` + } +) + +func main() { + fmt.Println("=== Mapper 配置项完整示例 ===") + fmt.Println() + + // 创建 Mapper 实例 + m := mapper.NewMapper() + + // ========== 配置项说明 ========== + fmt.Println("--- Mapper 配置项 ---") + fmt.Println() + + // 1. 类型检查 + fmt.Println("1. SetEnabledTypeChecking - 类型检查") + fmt.Println(" 开启后,映射时会检查字段类型是否一致") + fmt.Println(" 默认: false") + m.SetEnabledTypeChecking(true) + fmt.Printf(" 当前: %v\n", m.IsEnabledTypeChecking()) + fmt.Println() + + // 2. Mapper Tag + fmt.Println("2. SetEnabledMapperTag - mapper 标签") + fmt.Println(" 开启后,支持使用 mapper:\"field\" 标签映射") + fmt.Println(" 默认: true") + m.SetEnabledMapperTag(false) + fmt.Printf(" 当前: %v\n", m.IsEnabledMapperTag()) + m.SetEnabledMapperTag(true) // 恢复默认 + fmt.Println() + + // 3. Json Tag + fmt.Println("3. SetEnabledJsonTag - json 标签") + fmt.Println(" 开启后,支持使用 json:\"field\" 标签映射") + fmt.Println(" 默认: true") + m.SetEnabledJsonTag(false) + fmt.Printf(" 当前: %v\n", m.IsEnabledJsonTag()) + m.SetEnabledJsonTag(true) // 恢复默认 + fmt.Println() + + // 4. 自动类型转换 + fmt.Println("4. SetEnabledAutoTypeConvert - 自动类型转换") + fmt.Println(" 开启后,自动支持 Time 与 int64 (Unix时间戳) 互转") + fmt.Println(" 默认: true") + m.SetEnabledAutoTypeConvert(false) + fmt.Printf(" 当前: %v\n", m.IsEnabledAutoTypeConvert()) + m.SetEnabledAutoTypeConvert(true) // 恢复默认 + fmt.Println() + + // 5. 结构体字段映射 + fmt.Println("5. SetEnabledMapperStructField - 结构体字段映射") + fmt.Println(" 开启后,支持嵌套结构体的自动映射") + fmt.Println(" 默认: true") + m.SetEnabledMapperStructField(false) + fmt.Printf(" 当前: %v\n", m.IsEnabledMapperStructField()) + m.SetEnabledMapperStructField(true) // 恢复默认 + fmt.Println() + + // 6. 自定义标签 + fmt.Println("6. SetEnabledCustomTag - 自定义标签") + fmt.Println(" 开启后,可以使用自定义标签名进行映射") + fmt.Println(" 默认: false") + m.SetEnabledCustomTag(true) + m.SetCustomTagName("form") + fmt.Printf(" 当前: enabled=%v, tag=%s\n", m.IsEnabledCustomTag(), m.GetCustomTagName()) + m.SetEnabledCustomTag(false) // 恢复默认 + fmt.Println() + + // 7. 字段忽略标签 + fmt.Println("7. SetEnableFieldIgnoreTag - 字段忽略标签") + fmt.Println(" 开启后,支持使用 mapper:\"-\" 忽略字段") + fmt.Println(" 默认: false") + m.SetEnableFieldIgnoreTag(true) + fmt.Printf(" 当前: %v\n", m.IsEnableFieldIgnoreTag()) + m.SetEnableFieldIgnoreTag(false) // 恢复默认 + fmt.Println() + + // ========== 配置演示 ========== + fmt.Println("--- 配置演示 ---") + fmt.Println() + + // 重置所有配置 + m.SetEnabledMapperTag(true) + m.SetEnabledJsonTag(true) + m.SetEnabledAutoTypeConvert(true) + m.SetEnabledMapperStructField(true) + m.SetEnabledCustomTag(false) + + // 示例: 使用默认配置映射 + source1 := Source{ + ID: 1, + Name: "张三", + Age: 28, + Email: "zhangsan@example.com", + Password: "secret123", + Private: "hidden", + } + + var target1 Target + err := m.Mapper(source1, &target1) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 源: %+v\n", source1) + fmt.Printf(" 目标: %+v\n", target1) + } + fmt.Println() + + // 示例: 使用自定义标签 + m.SetEnabledCustomTag(true) + m.SetCustomTagName("form") + + type FormTarget struct { + ID int64 `form:"id"` + Name string `form:"name"` + Age int `form:"age"` + } + + source2 := Source{ + ID: 2, + Name: "李四", + Age: 32, + } + + var target2 FormTarget + err = m.Mapper(source2, &target2) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 使用 form 标签映射:\n") + fmt.Printf(" 源: %+v\n", source2) + fmt.Printf(" 目标: %+v\n", target2) + } + fmt.Println() + + // ========== 全局配置 ========== + fmt.Println("--- 全局配置 (standardMapper) ---") + fmt.Println() + + // 设置全局配置 + mapper.SetEnabledTypeChecking(true) + mapper.SetEnabledMapperTag(true) + mapper.SetEnabledJsonTag(true) + + source3 := Source{ + ID: 3, + Name: "王五", + Age: 35, + } + + var target3 Target + err = mapper.Mapper(source3, &target3) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 使用全局配置映射:\n") + fmt.Printf(" 源: %+v\n", source3) + fmt.Printf(" 目标: %+v\n", target3) + } + fmt.Println() + + // ========== 获取类型名称 ========== + fmt.Println("--- 其他功能 ---") + fmt.Println() + + typeName := m.GetTypeName(source1) + fmt.Printf(" GetTypeName: %s\n", typeName) + + fmt.Println() + fmt.Println("=== 示例完成 ===") +} diff --git a/example/error/main.go b/example/error/main.go new file mode 100644 index 0000000..2f9ccb3 --- /dev/null +++ b/example/error/main.go @@ -0,0 +1,161 @@ +package main + +import ( + "errors" + "fmt" + + "github.com/devfeel/mapper" +) + +// 定义测试结构体 +type ( + User struct { + ID int64 `mapper:"id"` + Name string `mapper:"name"` + Age int `mapper:"age"` + } + + UserDTO struct { + ID int64 `json:"id"` + Name string `json:"name"` + Age int `json:"age"` + } + + // 不可导出的结构体 (首字母小写) + secretUser struct { + ID int64 + Name string + } +) + +func main() { + fmt.Println("=== 错误处理场景示例 ===") + fmt.Println() + + // 示例1: nil 值处理 + fmt.Println("1. nil 值处理") + var nilUser *User = nil + result := mapper.MapDirectPtr[User, UserDTO](nilUser) + fmt.Printf(" 输入: nil 指针\n") + fmt.Printf(" 输出: %v\n", result) + fmt.Println() + + // 示例2: 空切片处理 + fmt.Println("2. 空切片处理") + emptyUsers := []User{} + resultSlice := mapper.MapDirectSlice[User, UserDTO](emptyUsers) + fmt.Printf(" 输入: 空切片 (len=0)\n") + fmt.Printf(" 输出: %v (len=%d)\n", resultSlice, len(resultSlice)) + fmt.Println() + + // 示例3: nil 切片处理 + fmt.Println("3. nil 切片处理") + var nilUsers []User = nil + resultNilSlice := mapper.MapDirectSlice[User, UserDTO](nilUsers) + fmt.Printf(" 输入: nil 切片\n") + fmt.Printf(" 输出: %v\n", resultNilSlice) + fmt.Println() + + // 示例4: SafeMapDirect 错误处理 + fmt.Println("4. SafeMapDirect 错误处理") + user4 := User{ID: 1, Name: "张三", Age: 28} + + // 正常情况 + dto4, err := mapper.SafeMapDirect[User, UserDTO](user4) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 成功: %+v\n", dto4) + } + fmt.Println() + + // 示例5: SafeMapDirectSlice 错误处理 + fmt.Println("5. SafeMapDirectSlice 错误处理") + users5 := []User{ + {ID: 1, Name: "用户1", Age: 20}, + {ID: 2, Name: "用户2", Age: 25}, + } + + dtos5, err := mapper.SafeMapDirectSlice[User, UserDTO](users5) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 成功: %d 条\n", len(dtos5)) + } + fmt.Println() + + // 示例6: 类型不匹配情况 + fmt.Println("6. 类型不匹配情况") + type UserWrong struct { + ID string `mapper:"id"` // string 而不是 int64 + Name string `mapper:"name"` + Age int `mapper:"age"` + } + + type UserDTOWrong struct { + ID int64 `json:"id"` + Name string `json:"name"` + Age int `json:"age"` + } + + userWrong := UserWrong{ID: "1", Name: "测试", Age: 20} + // 由于类型不匹配,映射结果可能不正确 + resultWrong := mapper.MapDirect[UserWrong, UserDTOWrong](userWrong) + fmt.Printf(" 注意: 类型不匹配时,结果可能不符合预期\n") + fmt.Printf(" 源 ID 类型: %T, 值: %v\n", userWrong.ID, userWrong.ID) + fmt.Printf(" 目标 ID 类型: %T, 值: %v\n", resultWrong.ID, resultWrong.ID) + fmt.Println() + + // 示例7: 使用传统 Mapper 的错误处理 + fmt.Println("7. 传统 Mapper 的错误处理") + m := mapper.NewMapper() + m.SetEnabledTypeChecking(true) + + user7 := &User{ID: 1, Name: "王五", Age: 30} + userDTO7 := &UserDTO{} + + err = m.Mapper(user7, userDTO7) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 成功: %+v\n", userDTO7) + } + fmt.Println() + + // 示例8: MapToSlice 错误处理 + fmt.Println("8. MapToSlice 错误处理") + fromMaps := map[string]interface{}{ + "user1": map[string]interface{}{"id": int64(1), "name": "赵六", "age": 35}, + "user2": map[string]interface{}{"id": int64(2), "name": "孙七", "age": 40}, + } + + var toSlice []UserDTO + err = m.MapToSlice(fromMaps, &toSlice) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 成功: %d 条\n", len(toSlice)) + for _, u := range toSlice { + fmt.Printf(" - %+v\n", u) + } + } + fmt.Println() + + // 示例9: 自定义错误处理逻辑 + fmt.Println("9. 自定义错误处理") + customErr := errors.New("自定义错误: 名称不能为空") + fmt.Printf(" 可以返回自定义错误: %v\n", customErr) + fmt.Println() + + // 示例10: 清除缓存后重新映射 + fmt.Println("10. 清除缓存后重新映射") + mapper.ClearFieldMappingCache() + fmt.Println(" 已清除字段映射缓存") + fmt.Println() + + fmt.Println("=== 错误处理总结 ===") + fmt.Println("1. MapDirect/MapDirectPtr - 不返回错误,适用于简单场景") + fmt.Println("2. SafeMapDirect/SafeMapDirectSlice - 返回错误,适用于需要错误处理的场景") + fmt.Println("3. 传统 Mapper 方法 - 支持更复杂的配置和错误处理") + fmt.Println("4. 使用 nil 值时,建议使用 SafeMapDirect 系列函数") +} diff --git a/example/function_test/main.go b/example/function_test/main.go index 12dab9a..894c6db 100644 --- a/example/function_test/main.go +++ b/example/function_test/main.go @@ -64,7 +64,7 @@ type Item struct { } func main() { - fmt.Println("=== Mapper Function Tests ===\n") + fmt.Println("=== Mapper Function Tests ===") // Test 1: Basic Mapper testBasicMapper() diff --git a/example/map/main.go b/example/map/main.go new file mode 100644 index 0000000..11f0cd5 --- /dev/null +++ b/example/map/main.go @@ -0,0 +1,144 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/devfeel/mapper" +) + +// 定义测试结构体 +type ( + // 用户结构体 + User struct { + ID int64 `mapper:"id"` + Name string `mapper:"name"` + Email string `mapper:"email"` + Age int `mapper:"age"` + Username string `json:"username"` + } + + // 用户DTO + UserDTO struct { + ID int64 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Age int `json:"age"` + Username string `json:"username"` + } +) + +func main() { + fmt.Println("=== Map 与 Struct 互转示例 ===") + fmt.Println() + + // 示例1: Struct -> Map + fmt.Println("1. Struct -> Map") + user := User{ + ID: 1, + Name: "张三", + Email: "zhangsan@example.com", + Age: 28, + Username: "zhangsan", + } + + userMap := make(map[string]interface{}) + err := mapper.AutoMapper(user, &userMap) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 源: %+v\n", user) + fmt.Printf(" Map: %v\n", userMap) + } + fmt.Println() + + // 示例2: Map -> Struct + fmt.Println("2. Map -> Struct") + valMap := map[string]interface{}{ + "id": int64(2), + "name": "李四", + "email": "lisi@example.com", + "age": 32, + "username": "lisi", + } + + var user2 User + err = mapper.MapperMap(valMap, &user2) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" Map: %v\n", valMap) + fmt.Printf(" Struct: %+v\n", user2) + } + fmt.Println() + + // 示例3: Struct -> JSON + fmt.Println("3. Struct -> JSON") + user3 := User{ + ID: 3, + Name: "王五", + Email: "wangwu@example.com", + Age: 35, + Username: "wangwu", + } + + jsonBytes, err := mapper.MapToJson(map[string]interface{}{ + "id": user3.ID, + "name": user3.Name, + "email": user3.Email, + "age": user3.Age, + "username": user3.Username, + }) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" JSON: %s\n", string(jsonBytes)) + } + fmt.Println() + + // 示例4: JSON -> Struct + fmt.Println("4. JSON -> Struct") + jsonStr := `{"id":4,"name":"赵六","email":"zhaoliu@example.com","age":40,"username":"zhaoliu"}` + + var jsonMap map[string]interface{} + err = json.Unmarshal([]byte(jsonStr), &jsonMap) + if err != nil { + fmt.Printf(" JSON解析错误: %v\n", err) + } else { + var user4 User + err = mapper.MapperMap(jsonMap, &user4) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" JSON: %s\n", jsonStr) + fmt.Printf(" Struct: %+v\n", user4) + } + } + fmt.Println() + + // 示例5: 使用 NewMapper 自定义配置 + fmt.Println("5. 使用 NewMapper 自定义配置") + m := mapper.NewMapper() + m.SetEnabledTypeChecking(true) + m.SetEnabledJsonTag(true) + + user5 := User{ + ID: 5, + Name: "孙七", + Email: "sunqi@example.com", + Age: 45, + Username: "sunqi", + } + + var userDTO5 UserDTO + err = m.Mapper(user5, &userDTO5) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 源: %+v\n", user5) + fmt.Printf(" DTO: %+v\n", userDTO5) + } + fmt.Println() + + fmt.Println("=== 示例完成 ===") +} diff --git a/example/slice/main.go b/example/slice/main.go new file mode 100644 index 0000000..a8a9bae --- /dev/null +++ b/example/slice/main.go @@ -0,0 +1,160 @@ +package main + +import ( + "fmt" + + "github.com/devfeel/mapper" +) + +// 定义测试结构体 +type ( + // 源结构体 + SourceUser struct { + ID int64 `mapper:"id"` + Name string `mapper:"name"` + Email string `mapper:"email"` + Age int `mapper:"age"` + CreatedAt int64 `mapper:"created_at"` + Score float64 + Status int + } + + // 目标结构体 - DTO + UserDTO struct { + ID int64 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Age int `json:"age"` + CreatedAt int64 `json:"created_at"` + Score float64 `json:"score"` + Status int `json:"status"` + } + + // 目标结构体 - VO (不同字段) + UserVO struct { + UserID int64 `json:"user_id"` + UserName string `json:"user_name"` + Email string `json:"email"` + Age int `json:"age"` + CreatedAt int64 `json:"created_at"` + Score float64 `json:"score"` + IsActive bool `json:"is_active"` + } +) + +func main() { + fmt.Println("=== Slice 批量映射进阶示例 ===") + fmt.Println() + + // 准备测试数据 + users := []SourceUser{ + {ID: 1, Name: "张三", Email: "zhangsan@example.com", Age: 28, CreatedAt: 1704067200, Score: 95.5, Status: 1}, + {ID: 2, Name: "李四", Email: "lisi@example.com", Age: 32, CreatedAt: 1704153600, Score: 88.0, Status: 1}, + {ID: 3, Name: "王五", Email: "wangwu@example.com", Age: 35, CreatedAt: 1704240000, Score: 92.0, Status: 0}, + {ID: 4, Name: "赵六", Email: "zhaoliu@example.com", Age: 40, CreatedAt: 1704326400, Score: 85.5, Status: 1}, + {ID: 5, Name: "孙七", Email: "sunqi@example.com", Age: 45, CreatedAt: 1704412800, Score: 90.0, Status: 0}, + } + + // 示例1: 基本 Slice 映射 + fmt.Println("1. 基本 Slice 映射 (同构类型)") + userCopies := mapper.MapDirectSlice[SourceUser, SourceUser](users) + fmt.Printf(" 源数量: %d, 目标数量: %d\n", len(users), len(userCopies)) + fmt.Println() + + // 示例2: 异构类型映射 + fmt.Println("2. 异构类型映射 (SourceUser -> UserDTO)") + userDTOs := mapper.MapDirectSlice[SourceUser, UserDTO](users) + fmt.Printf(" 源数量: %d, 目标数量: %d\n", len(users), len(userDTOs)) + for i, u := range userDTOs { + fmt.Printf(" [%d] ID=%d Name=%s Score=%.1f\n", i, u.ID, u.Name, u.Score) + } + fmt.Println() + + // 示例3: 指针 Slice 映射 + fmt.Println("3. 指针 Slice 映射") + userPtrs := []*SourceUser{ + {ID: 10, Name: "周八", Email: "zhouba@example.com", Age: 50, CreatedAt: 1704499200, Score: 98.0, Status: 1}, + {ID: 11, Name: "吴九", Email: "wujiu@example.com", Age: 55, CreatedAt: 1704585600, Score: 87.5, Status: 1}, + } + userDTOPtrs := mapper.MapDirectPtrSlice[SourceUser, UserDTO](userPtrs) + fmt.Printf(" 源数量: %d, 目标数量: %d\n", len(userPtrs), len(userDTOPtrs)) + for i, u := range userDTOPtrs { + if u != nil { + fmt.Printf(" [%d] ID=%d Name=%s\n", i, u.ID, u.Name) + } + } + fmt.Println() + + // 示例4: 切片截取映射 + fmt.Println("4. 切片截取映射") + largeUsers := make([]SourceUser, 100) + for i := 0; i < 100; i++ { + largeUsers[i] = SourceUser{ + ID: int64(i), + Name: fmt.Sprintf("用户%d", i), + Email: fmt.Sprintf("user%d@example.com", i), + Age: 20 + i%50, + CreatedAt: 1704067200 + int64(i*86400), + Score: float64(60 + i%40), + Status: i % 2, + } + } + + // 取前10个 + subset := largeUsers[:10] + subsetDTOs := mapper.MapDirectSlice[SourceUser, UserDTO](subset) + fmt.Printf(" 源切片: 前10个\n") + fmt.Printf(" 映射结果: %d 条\n", len(subsetDTOs)) + fmt.Println() + + // 示例5: 过滤后映射 (使用传统方式) + fmt.Println("5. 过滤后映射 (状态为1的用户)") + var activeUsers []SourceUser + for _, u := range users { + if u.Status == 1 { + activeUsers = append(activeUsers, u) + } + } + activeDTOs := mapper.MapDirectSlice[SourceUser, UserDTO](activeUsers) + fmt.Printf(" 过滤前: %d 条, 过滤后: %d 条\n", len(users), len(activeDTOs)) + for _, u := range activeDTOs { + fmt.Printf(" - %s (Status=%d)\n", u.Name, u.Status) + } + fmt.Println() + + // 示例6: 大批量映射 (1000条) + fmt.Println("6. 大批量映射 (1000条)") + veryLargeUsers := make([]SourceUser, 1000) + for i := 0; i < 1000; i++ { + veryLargeUsers[i] = SourceUser{ + ID: int64(i), + Name: fmt.Sprintf("用户%d", i), + Email: fmt.Sprintf("user%d@example.com", i), + Age: 20 + i%50, + CreatedAt: 1704067200, + Score: float64(60 + i%40), + Status: i % 2, + } + } + + // 使用并行映射 (阈值>=1000) + result := mapper.MapDirectSlice[SourceUser, UserDTO](veryLargeUsers) + fmt.Printf(" 映射 1000 条数据,结果: %d 条\n", len(result)) + fmt.Println() + + // 示例7: 错误处理 + fmt.Println("7. 安全映射 (带错误处理)") + usersWithError := []SourceUser{ + {ID: 1, Name: "正常用户", Email: "test@example.com", Age: 25, CreatedAt: 1704067200, Score: 90.0, Status: 1}, + } + // 注意: SafeMapDirectSlice 会返回错误 + resultWithError, err := mapper.SafeMapDirectSlice[SourceUser, UserDTO](usersWithError) + if err != nil { + fmt.Printf(" 错误: %v\n", err) + } else { + fmt.Printf(" 成功映射: %d 条\n", len(resultWithError)) + } + fmt.Println() + + fmt.Println("=== 示例完成 ===") +}