# sc **Repository Path**: vipkwds/sc ## Basic Information - **Project Name**: sc - **Description**: `sc` 是基于**策略模式**的 Go 通用类型转换库,支持**编译期类型安全**(泛型)和**运行时动态类型转换**两种模式 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-12 - **Last Updated**: 2026-06-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SmartConvert (sc) - 智能类型转换库 ## 概述 `sc` 是基于**策略模式**的 Go 通用类型转换库,支持**编译期类型安全**(泛型)和**运行时动态类型转换**两种模式。 ### 核心特性 - **策略模式**:18 个内置转换器,支持自定义扩展 - **泛型支持**:编译期类型安全 - **动态转换**:通过字符串指定目标类型,支持复杂嵌套类型 - **严格模式**:可选严格模式,收集所有转换错误 - **高性能**:结构体字段元数据缓存 - **线程安全**:并发安全的注册表和错误收集 - **JSON 虚拟化**:自动解析 JSON 字符串为目标类型 - **智能匹配**:json tag 优先,Go field 名降级匹配 - **inline 支持**:支持 `json:",inline"` 嵌入结构体平铺展开,冲突字段可选 shadowing 或双写策略 --- ## 安装 ```bash go get gitee.com/vipkwds/sc ``` ### 版本要求 - Go 1.24.4 或更高版本 --- ## 公开 API ### 1. 泛型 API(编译期类型安全) ```go // 基础转换,返回 (dest, ok) // inlineUnShadow: inline 字段冲突时双写(true)还是 shadowing(false,默认) func SmartConvert[Dest any](src any, inlineUnShadow ...bool) (dest Dest, ok bool) // 带详细错误的转换,返回 (dest, err) func SmartConvertWithError[Dest any](src any, inlineUnShadow ...bool) (dest Dest, err error) // 严格模式转换,收集所有错误,返回 (dest, ok, errors) func SmartConvertStrict[Dest any](src any, inlineUnShadow ...bool) (dest Dest, ok bool, errors []error) // 带选项的严格模式转换 func SmartConvertStrictWithOptions[Dest any](src any, opts ConvertOptions) (dest Dest, ok bool, errors []error) ``` ### 2. 动态类型转换 API(运行时) ```go // 通过字符串指定目标类型,支持复杂嵌套类型 // inlineUnShadow: inline 字段冲突时双写(true)还是 shadowing(false,默认) func ConvertType(src any, destType string, inlineUnShadow ...bool) (any, bool, error) // 注册结构体类型(用于动态类型转换) func RegisterStructType(typeName string, t reflect.Type) ``` --- ## 支持的类型转换 ### 基础类型 | 源类型 | 目标类型 | 示例 | | -------- | ---------- | ------ | | `int` 系列 | `int` 系列 | `int` → `int64`, `int32` → `int8` | | `uint` 系列 | `uint` 系列 | `uint` → `uint32` | | `float` 系列 | `float` 系列 | `float64` → `float32` | | `int` 系列 | `float` 系列 | `int` → `float64` | | `float` 系列 | `int` 系列 | `float64` → `int` (截断小数) | | `int` 系列 | `bool` | `42` → `true`, `0` → `false` | | `bool` | `int` 系列 | `true` → `1`, `false` → `0` | ### 字符串转换 | 源类型 | 目标类型 | 示例 | | -------- | ---------- | ------ | | `string` | `int` 系列 | `"123"` → `123` | | `string` | `float` 系列 | `"3.14"` → `3.14` | | `string` | `bool` | `"true"`, `"1"`, `"yes"`, `"on"` → `true` | | `int` 系列 | `string` | `42` → `"42"` | | `float` 系列 | `string` | `3.14` → `"3.14"` (保持完整精度) | | `bool` | `string` | `true` → `"true"` | ### Slice/Array 转换 | 源类型 | 目标类型 | 示例 | | -------- | ---------- | ------ | | `[]int` | `[]int64` | `[1,2,3]` → `[1,2,3]` | | `[]string` | `[]int` | `["1","2"]` → `[1,2]` | | `[]byte` | `string` | `[104,101,108,108,111]` → `"hello"` | | `[]rune` | `string` | `[0x4E2D]` → `"中"` | | `string` | `[]byte` | `"hello"` → `[104,101,108,108,111]` | | `string` | `[]rune` | `"hello"` → `[104,101,108,108,111]` | ### Map/Struct 转换 | 源类型 | 目标类型 | 示例 | | -------- | ---------- | ------ | | `map[string]any` | `Struct` | `{"name":"Tom"}` → `Person{Name:"Tom"}` | | `map[any]any` | `Struct` | 同样支持,自动匹配字段 | | `Struct` | `map[string]any` | `Person{Name:"Tom"}` → `{"name":"Tom"}` | | `map[K]V` | `map[K]V` | `map[string]int` → `map[any]any` | | 嵌套 Map | 嵌套 Struct | `{"addr":{"city":"北京"}}` → `{Address:{City:"北京"}}` | ### time.Time 转换 | 源类型 | 目标类型 | 示例 | | -------- | ---------- | ------ | | `time.Time` | `string` | `time.Now()` → `"2024-01-15T10:30:00Z"` | | `string` | `time.Time` | `"2024-01-15"` → `time.Time{}` | 支持的日期格式:RFC3339, RFC3339Nano, `2006-01-02T15:04:05`, `2006-01-02 15:04:05`, `2006-01-02`, `2006/01/02`, `02/01/2006`, `01/02/2006` ### 指针类型 | 源类型 | 目标类型 | 示例 | | -------- | ---------- | ------ | | `*T` | `T` | `*int(100)` → `100` | | `T` | `*T` | `100` → `*int(100)` | --- ## 特殊功能 ### JSON 字符串自动虚拟化 当目标类型为非基础类型时,`SmartConvert` 会自动检测并解析 JSON 字符串: ```go // JSON 字符串 -> Struct jsonStr := `{"Name": "Tom", "Age": 14}` person, ok := SmartConvert[Person](jsonStr) // person = {Name:"Tom", Age:14}, ok = true // JSON 字符串 -> Map result, ok := SmartConvert[map[string]any](jsonStr) // result = {"Name":"Tom", "Age":14}, ok = true // JSON 数组字符串 -> Slice arrStr := `[1, 2, 3]` nums, ok := SmartConvert[[]int](arrStr) // nums = [1, 2, 3], ok = true ``` **基础类型保护**:目标为 `string` 时,不会被错误解析为 JSON ```go // 普通字符串不会被解析 result, ok := SmartConvert[string]("[1, 2, 3]") // result = "[1, 2, 3]", ok = true (保持原字符串) ``` ### map[any]any 支持 支持 `map[any]any` 类型作为源或目标: ```go // []map[any]any -> []Struct data := []map[any]any{ {"Name": "x", "Id": 111}, } roles, ok := SmartConvert[[]Role](data) // roles = [{Name:"x", Id:111}], ok = true ``` ### json tag omitempty `json:"name,omitempty"` 标签在 Struct → Map 转换时生效: ```go type Person struct { Name string `json:"name,omitempty"` Email string `json:"email,omitempty"` } p := Person{Name: "Tom", Email: ""} m, _ := SmartConvert[map[string]any](p) // m = {"name":"Tom"} (Email 因 omitempty + 零值被跳过) ``` ### 字段匹配优先级 Map → Struct 时,字段匹配优先级: 1. **json tag**(优先) 2. **Go field 名**(降级) ```go data := map[string]any{"Name": "Tom", "Id": 111} role, ok := SmartConvert[Role](data) // Role 字段: Name string `json:"name"`, Id int64 `json:"id"` // "Name" 匹配失败,降级匹配 "name" (json tag) ✓ // "Id" 匹配失败,降级匹配 "id" (json tag) ✓ ``` --- ## ConvertType 支持的类型字符串 ### 基础类型 ```go "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "bool", "string", "any", "interface{}" ``` ### 切片类型 ```go "[]int", "[]int64", "[]string", "[]bool", "[]float64", "[]byte", "[]rune", "[]any" ``` ### Map 类型 ```go "map[string]any", "map[string]int", "map[string]string", "map[any]any", "map[any]string" ``` ### 复杂嵌套类型 ```go "map[string][]any" // map 的 value 是 slice "map[string]map[string]any" // map 的 value 是嵌套 map "[]map[string]any" // slice 元素是 map ``` ### 注册的自定义类型 ```go // 需要先注册 RegisterStructType("main.Person", reflect.TypeOf(Person{})) ConvertType(src, "main.Person") ``` ### JSON 序列化类型 ```go // "jsontext" 或 "json":将任意类型序列化为 JSON 字符串 ConvertType(Person{Name: "Tom", Age: 14}, "jsontext") // 返回: `{"Name":"Tom","Age":14}` ConvertType([]int{1, 2, 3}, "json") // 返回: `[1,2,3]` ``` --- ## 使用示例 ### 1. 基础类型转换 ```go // int 转 float64 val, ok := SmartConvert[float64](42) // val = 42.0, ok = true // string 转 int num, ok := SmartConvert[int]("123") // num = 123, ok = true // float 转 bool (非0=true) flag, ok := SmartConvert[bool](3.14) // flag = true, ok = true ``` ### 2. JSON 字符串直接转换 ```go // JSON -> Struct jsonStr := `{"Name": "Tom", "Age": 14, "Roles": [{"Name": "x", "Id": 111}]}` person, ok := SmartConvert[Person](jsonStr) // JSON -> []Struct jsonArr := `[{"Name": "x", "Id": 111}]` roles, ok := SmartConvert[[]Role](jsonArr) ``` ### 3. Slice 转换 ```go // []string 转 []int nums, ok := SmartConvert[[]int]([]string{"1", "2", "3"}) // nums = [1, 2, 3], ok = true ``` ### 4. Map ↔ Struct 转换 ```go type Person struct { Name string `json:"name"` Age int `json:"age"` } // Map -> Struct data := map[string]any{"name": "Tom", "age": 25} person, ok := SmartConvert[Person](data) // person = {Name:"Tom", Age:25}, ok = true // Struct -> Map m, ok := SmartConvert[map[string]any](Person{Name: "Jerry", Age: 30}) // m = {"name":"Jerry", "age":30}, ok = true ``` ### 5. 嵌套转换 ```go type Address struct { City string `json:"city"` } type User struct { Name string `json:"name"` Address Address `json:"address"` } data := map[string]any{ "name": "张三", "address": map[string]any{ "city": "北京", }, } user, ok := SmartConvert[User](data) // user = {Name:"张三", Address:{City:"北京"}}, ok = true ``` ### 6. 严格模式 ```go type Person struct { Name string Age int } data := map[string]any{"Name": "Tom", "Age": "not_a_number"} person, ok, errs := SmartConvertStrict[Person](data) // ok = false, errs = [field "Age": invalid input type or value] // 非严格模式:跳过错误字段 person2, ok2 := SmartConvert[Person](data) // ok2 = true, person2 = {Name:"Tom", Age:0} ``` ### 7. time.Time 转换 ```go // time.Time -> string str, ok := SmartConvert[string](time.Now()) // str = "2024-01-15T10:30:00Z", ok = true // string -> time.Time tm, ok := SmartConvert[time.Time]("2024-01-01") // tm = 2024-01-01 00:00:00 +0800 CST, ok = true ``` ### 8. 动态类型转换 ```go // 基础类型 result, ok, err := ConvertType(42, "int64") // result = 64位整数 42, ok = true // 复杂嵌套类型 result, ok, err := ConvertType([]int{1, 2, 3}, "[]any") // result = []any{1, 2, 3}, ok = true // map[string][]any src := map[string]any{"a": 1, "b": []any{1, 2, 3}} result, ok, err := ConvertType(src, "map[string][]any") // result = map[string][]any{"a":0, "b":[1 2 3]}, ok = true // JSON 序列化类型:目标类型为 "jsontext" 或 "json",将任意类型序列化为 JSON 字符串 result, ok, err := ConvertType(Person{Name: "Tom", Age: 14}, "jsontext") // result = `{"Name":"Tom","Age":14}`, ok = true result, ok, err := ConvertType([]int{1, 2, 3}, "json") // result = `[1,2,3]`, ok = true ``` ### 9. 自定义结构体注册 ```go type User struct { Name string Age int } // 注册结构体类型 RegisterStructType("main.User", reflect.TypeOf(User{})) // 动态使用 result, ok, err := ConvertType(map[string]any{"Name": "Tom", "Age": 25}, "main.User") // result = User{Name:"Tom", Age:25}, ok = true ``` ### 10. 溢出检测 ```go // int8 范围: -128 ~ 127 val, ok := SmartConvert[int8](200) // ok = false (溢出) val, ok := SmartConvert[int8](-200) // ok = false (溢出) // 负数转 uint val, ok := SmartConvert[uint](-1) // ok = false // NaN/Inf 转 int val, ok := SmartConvert[int](math.NaN()) // ok = false val, ok := SmartConvert[int](math.Inf(1)) // ok = false ``` --- ## 错误处理 ### 错误类型 ```go var ( ErrInvalidInput = errors.New("invalid input type or value") ErrOverflow = errors.New("value overflow for target type") ErrUnsupportedType = errors.New("unsupported type conversion") ErrNilPointer = errors.New("nil pointer encountered") ) ``` ### 三种错误处理模式 ```go // 1. 简单布尔模式(默认) val, ok := SmartConvert[int](src) // ok = true 表示成功,false 表示失败 // 2. 详细错误模式 val, err := SmartConvertWithError[int](src) // err != nil 表示失败,可获取具体错误原因 // 3. 严格错误收集模式 val, ok, errs := SmartConvertStrict[Person](src) // errs 包含所有转换失败的信息 ``` --- ## 性能优化 ### 结构体字段缓存 ```go // 内置缓存机制,相同结构体只解析一次 var structCache sync.Map type structMeta struct { Fields []fieldMeta // 字段元数据列表 HasTag bool // 是否有 json tag } ``` ### 并发安全 - `sync.Map` 存储结构体元数据缓存 - `sync.Mutex` 保护错误列表 - `sync.RWMutex` 保护转换器注册表 - `recover()` 保护 map key 不可比较时的 panic --- ## 注意事项 ### 1. inline 嵌入结构体支持 `sc` 支持 Go 的 `json:",inline"` 标签,将嵌入结构体的字段平铺到父结构体层级。 ```go type Person struct { Name string Age int Roles []Role } type demo struct { Person `json:",inline"` // Person 的字段将平铺到 demo Level int } ``` **冲突处理策略**(通过 `inlineUnShadow` 参数控制): | 模式 | `inlineUnShadow=false`(默认) | `inlineUnShadow=true` | | ------ | ------------------------------- | ---------------------- | | 行为 | 外层字段优先,inline 字段被 shadow为零值 | 冲突字段双写 | | 示例 | `demo.Name="Tom", Person.Name=""` | `demo.Name="Tom", Person.Name="Tom"` | | 符合 | Go 标准 `encoding/json` 行为 | 业务友好,数据不丢失 | ```go // 默认 shadowing(符合 Go 标准) person1, ok := sc.SmartConvert[demo](data) // Person.Name 被 shadow为零值 // 双写策略(业务友好) person2, ok := sc.SmartConvert[demo](data, true) // 冲突字段双写 ``` ### 2. 严格模式 vs 非严格模式 - **非严格模式**:转换失败的字段使用零值,继续处理其他字段 - **严格模式**:收集所有转换错误 ### 3. 数值溢出 - `int` → `int8` 当值超出 `[-128, 127]` 范围时返回失败 - `float` → `int` 当值为 `NaN` 或 `Inf` 时返回失败 - 负数转 `uint` 返回失败 ### 4. JSON Tag 支持 ```go type Person struct { Name string `json:"name"` // 转换为 map 时使用 "name" 作为 key Age int `json:"age"` // 支持 omitempty、inline } ``` ### 5. 嵌套深度 - Map ↔ Struct 支持无限层级嵌套 - Slice 元素自动递归转换 ### 6. 指针解引用 - `*T` → `T`:自动解引用 - `T` → `*T`:自动取地址 - `nil` 指针返回 `ErrNilPointer` ### 7. interface{} 解包 - `interface{}` 值会被自动解包后再转换 - 解包后继续处理嵌套的 `interface{}` ### 8. 自定义结构体动态类型 由于 Go 反射限制,无法通过字符串动态创建结构体类型。需要: 1. 使用 `RegisterStructType` 预注册类型 2. 或使用 `SmartConvert[Dest]` 泛型方式 ### 9. 字段匹配规则 匹配优先级(由高到低): 1. **json tag 精确匹配**:`json:"name"` 精确匹配 key "name" 2. **Go field 名精确匹配**:字段名 "Name" 精确匹配 key "Name" 3. **大小写不敏感匹配**:字段名 "Name" 匹配 key "name"(符合 Go json 标准行为) 当 json tag 和 field 名都匹配失败时,自动降级尝试大小写不敏感匹配 --- ## 设计模式 ### 策略模式 ```go type typeConverter interface { match(srcKind, destKind reflect.Kind, srcType, destType reflect.Type) bool convert(ctx *conversionContext, src, dest reflect.Value) error } ``` ### 转换器注册表 ```go var registry = &converterRegistry{ converters: []typeConverter{}, mu: sync.RWMutex{}, } ``` ### 内置转换器列表(18 个) 1. `mapToStructConverter` - Map → Struct 2. `structToMapConverter` - Struct → Map 3. `mapToMapConverter` - Map → Map 4. `timeToStringConverter` - time.Time → string 5. `stringToTimeConverter` - string → time.Time 6. `numericToNumericConverter` - 数值 → 数值 7. `numericToBoolConverter` - 数值 → bool 8. `stringToNumericConverter` - 字符串 → 数值 9. `numericToStringConverter` - 数值 → 字符串 10. `boolConverter` - bool 转换 11. `stringToBoolConverter` - 字符串 → bool 12. `runeToStringConverter` - rune → string 13. `stringToStringConverter` - 字符串透传 14. `stringToBytesConverter` - string → []byte 15. `stringToRunesConverter` - string → []rune 16. `bytesToStringConverter` - []byte → string 17. `runesToStringConverter` - []rune → string 18. `sliceConverter` - slice 转换 --- ## 测试覆盖 ```bash # 运行所有测试 go test -v . go test -v -coverprofile=c.out && go tool cover -func=c.out # 运行特定测试 go test -v -run TestSmartConvert_Basic . go test -v -run TestConvertTypeComplex . ``` 测试覆盖场景: - 基础类型转换 - Slice/Array 转换 - Map ↔ Struct 转换 - 嵌套转换 - time.Time 转换 - 溢出检测 - 严格模式 - 并发安全 - 动态类型转换(含复杂嵌套类型) - 结构体类型注册 - JSON 字符串自动解析 - omitempty 支持