一个轻量级的高性能 Go 类型转换库。
go get github.com/graingo/mconv- 简单直观的 API
- 零依赖
- 全面的类型转换支持
- 线程安全
- 高性能缓存机制
- 泛型支持(Go 1.18+)
- 反射结果缓存
// 基本类型转换
str := mconv.ToString(123) // "123"
num := mconv.ToInt("123") // 123
b := mconv.ToBool(1) // true
f := mconv.ToFloat64("123.45") // 123.45
t := mconv.ToTime("2006-01-02") // time.Time
// 带错误处理
str, err := mconv.ToStringE(123) // "123", nil
num, err := mconv.ToIntE("abc") // 0, error
// 复杂类型转换
slice := mconv.ToSlice([]int{1, 2, 3}) // []interface{}{1, 2, 3}
strSlice := mconv.ToStringSlice([]int{1, 2, 3}) // []string{"1", "2", "3"}
m := mconv.ToMap(map[string]int{"a": 1}) // map[string]interface{}{"a": 1}
// JSON 转换
jsonStr := mconv.ToJSON(map[string]interface{}{"name": "John"}) // {"name":"John"}
personMap := mconv.ToMapFromJSON(`{"name":"Jane"}`) // map[string]interface{}{"name": "Jane"}mconv 包在 complex 子包中提供了一个强大的 Struct 函数 (以及它返回错误的版本 StructE)。这个工具专为将 map[string]interface{} 或其他 struct 灵活、高性能地转换为目标 struct 而设计。它利用缓存机制来优化重复转换,从而实现显著的速度提升。
主要特性:
- 简单转换: 直接将数据映射到结构体的字段。
- 标签驱动映射: 使用
mconv标签来映射不同名称的字段。 - 不区分大小写: 自动匹配源
map中的键和结构体字段,不限制大小写。 - 嵌套结构体: 递归地转换嵌套的
map或struct。 - 通过钩子扩展: 提供自定义的
HookFunc函数来处理特殊的转换逻辑。 - 高性能: 缓存结构体的分析结果,使得后续的转换非常快。
基础用法
package main
import (
"fmt"
"github.com/graingo/mconv/complex"
)
func main() {
type User struct {
ID int `mconv:"user_id"`
Name string `mconv:"user_name"`
}
source := map[string]interface{}{
"user_id": 123,
"USER_NAME": "Alice", // 不区分大小写匹配
}
var user User
err := complex.ToStructE(source, &user)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", user)
// Output: {ID:123 Name:Alice}
}使用钩子 (Hooks)
您可以使用钩子注入自定义的转换逻辑。例如,将一个整型的状态转换为字符串。
package main
import (
"fmt"
"github.com/graingo/mconv/complex"
"reflect"
)
func main() {
type Post struct {
Title string
Status string `mconv:"status"`
}
// 这个钩子将整型 status 转换为字符串表示
intStatusToStringHook := func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
if from.Kind() == reflect.Int && to.Kind() == reflect.String {
i, _ := data.(int)
switch i {
case 0:
return "Draft", nil
case 1:
return "Published", nil
default:
return "Unknown", nil
}
}
return data, nil
}
source := map[string]interface{}{
"Title": "Hello World",
"status": 1,
}
var post Post
err := complex.ToStructE(source, &post, intStatusToStringHook)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", post)
// Output: {Title:Hello World Status:Published}
}默认情况下, mconv 包含一个内置钩子,用于处理从 string 到 time.Time 的转换。
import "github.com/graingo/mconv/complex"
// 使用泛型进行切片转换
strSlice := complex.ToSliceT[string]([]int{1, 2, 3}) // []string{"1", "2", "3"}
intSlice := complex.ToSliceT[int]([]string{"1", "2", "3"}) // []int{1, 2, 3}
// 使用泛型进行映射转换
strMap := complex.ToMapT[string, string](map[string]int{"a": 1}) // map[string]string{"a": "1"}
intMap := complex.ToMapT[string, int](map[string]interface{}{"a": "1"}) // map[string]int{"a": 1}// 设置缓存大小
mconv.SetStringCacheSize(2000) // 设置字符串缓存大小(默认 1000)
mconv.SetTimeCacheSize(200) // 设置时间缓存大小(默认 100)
mconv.SetTypeInfoCacheSize(1000) // 设置类型信息缓存大小(默认 1000)
mconv.SetConversionCacheSize(1000) // 设置转换缓存大小(默认 1000)
// 清除缓存
mconv.ClearStringCache() // 清除字符串缓存
mconv.ClearTimeCache() // 清除时间缓存
mconv.ClearTypeInfoCache() // 清除类型信息缓存
mconv.ClearConversionCache() // 清除转换缓存
mconv.ClearAllCaches() // 清除所有缓存以下基准测试结果在 Apple M2 处理器上测量:
BenchmarkToString-8 13534419 107.5 ns/op 8 B/op 1 allocs/op
BenchmarkToInt-8 100000000 10.91 ns/op 0 B/op 0 allocs/op
BenchmarkToBool-8 178200254 6.75 ns/op 0 B/op 0 allocs/op
BenchmarkToFloat64-8 54603055 20.84 ns/op 0 B/op 0 allocs/op
BenchmarkToTime-8 15548144 76.57 ns/op 32 B/op 1 allocs/op
BenchmarkToSlice-8 35479252 33.26 ns/op 40 B/op 2 allocs/op
BenchmarkToStringSlice-8 3392653 364.7 ns/op 120 B/op 8 allocs/op
BenchmarkToMap-8 7964676 153.1 ns/op 336 B/op 2 allocs/op
BenchmarkToJSON-8 3466358 348.2 ns/op 192 B/op 7 allocs/op
泛型函数:
BenchmarkToSliceT-8 2906990 397.6 ns/op 136 B/op 6 allocs/op
BenchmarkToMapT-8 1654909 723.4 ns/op 688 B/op 7 allocs/op
结构体转换:
BenchmarkStructConversion-8 7186039 166.4 ns/op 0 B/op 0 allocs/op
BenchmarkStructConversionParallel-8 36372223 40.26 ns/op 0 B/op 0 allocs/op
反射缓存是 mconv 库的一个重要特性,它可以显著提高类型转换的性能。以下基准测试结果展示了反射缓存的性能优势:
BenchmarkReflectionCache_TypeInfo/WithoutCache-8 8842224 133.9 ns/op 56 B/op 7 allocs/op
BenchmarkReflectionCache_TypeInfo/WithCache-8 25792029 49.03 ns/op 0 B/op 0 allocs/op
从上述结果可以看出:
- 性能提升:使用反射缓存后,处理相同类型的反射操作速度提高了约 2.7 倍(从 133.9 ns/op 降至 49.03 ns/op)。
- 内存优化:使用缓存后,内存分配从每次操作 56 字节和 7 次分配减少到 0 字节和 0 次分配,完全消除了内存分配开销。
- 吞吐量提升:每秒可处理的操作数从约 880 万增加到约 2580 万,提高了约 192%。
对于大型数据结构,性能优势更加明显:
BenchmarkLargeSliceConversion/WithoutCache-8 9327 121340 ns/op 46738 B/op 1747 allocs/op
BenchmarkLargeSliceConversion/WithCache-8 9620 121506 ns/op 46738 B/op 1747 allocs/op
这些优势在处理大型数据集或需要频繁进行类型转换的应用中尤为明显。反射缓存通过存储类型信息和转换结果,避免了重复的反射操作,从而显著提高了性能。
反射缓存在以下场景中特别有用:
- API 服务:需要频繁将数据在不同格式之间转换
- 数据处理管道:处理大量结构相似的数据
- ORM 和数据映射:在数据库记录和结构体之间进行映射
- 配置处理:解析和转换各种格式的配置数据
- JSON/XML 处理:频繁进行序列化和反序列化操作
MIT 许可证