mirror of
https://github.com/jefferyjob/go-easy-utils.git
synced 2025-09-26 19:11:12 +08:00
del: 删除json转结构体老的方法 (#108)
This commit is contained in:
@@ -1,100 +0,0 @@
|
||||
# JsonToStruct 开发文档
|
||||
|
||||
## 处理指针类型
|
||||
|
||||
```go
|
||||
v := reflect.ValueOf(i)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return 0, nil // 检查解引用后的值是否为 nil
|
||||
}
|
||||
v = v.Elem() // 获取指针所指向的值
|
||||
}
|
||||
```
|
||||
|
||||
在`reflect`包中,指针类型和其指向的值的类型是不同的。例如,一个指向`int`类型的指针,其类型是`*int`,而其指向的值的类型是`int`。因此,在使用`reflect`包时,我们需要注意区分指针类型和其指向的值的类型,否则可能会出现类型错误等问题。
|
||||
|
||||
因此,对于`value`为指针类型的情况,我们需要通过Elem方法获取其指向的值,然后再进行类型转换。而在使用`Elem`方法之前,我们需要先检查v是否为指针类型,因此使用循环语句进行判断。
|
||||
|
||||
**举个例子**
|
||||
|
||||
```go
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func main() {
|
||||
p := &Person{"Tom", 18}
|
||||
v := reflect.ValueOf(p).Elem()
|
||||
name := v.FieldByName("Name")
|
||||
age := v.FieldByName("Age")
|
||||
|
||||
fmt.Println(name.String()) // 输出:Tom
|
||||
fmt.Println(age.Int()) // 输出:18
|
||||
|
||||
name.SetString("Jerry") // 修改 Name 字段的值
|
||||
age.SetInt(20) // 修改 Age 字段的值
|
||||
|
||||
fmt.Println(p.Name) // 输出:Jerry
|
||||
fmt.Println(p.Age) // 输出:20
|
||||
}
|
||||
```
|
||||
|
||||
在上面的例子中,我们首先将结构体指针 `p` 转换为 `reflect.Value` 类型的值 `v`,然后使用 `v.Elem()` 获取指针所指向的值,接着使用 `FieldByName()` 方法获取结构体字段的 `reflect.Value` 类型的值,最后使用 `SetString()` 和 `SetInt()` 方法修改结构体字段的值。
|
||||
|
||||
## 处理Slice数据类型
|
||||
|
||||
```go
|
||||
case reflect.Slice:
|
||||
if subData, ok := value.([]interface{}); ok {
|
||||
if err := parseSlice(fieldValue, subData); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("unexpected value type for slice: %T", value)
|
||||
}
|
||||
```
|
||||
|
||||
将每个子元素都转换为结构体定义的数据类型再赋值给对应的字段。如果子元素是一个切片类型,需要进行递归处理。
|
||||
|
||||
首先获取到切片的元素类型 subType,如果 subType 是一个指针类型,需要将其转换为实际的元素类型。然后创建一个与原始切片相同长度的新切片 subSliceValue,并循环遍历原始切片中的每个子元素。在每个子元素中,需要将其转换为结构体定义的数据类型,可以通过递归调用 parseStruct 或 parseSlice 来实现。最后,将新的子元素设置到新切片 subSliceValue 中,并将其赋值给对应的字段。注意,如果元素类型是一个结构体,需要使用 Set 方法设置到新切片中,如果是基本类型,则需要判定类型然后添加到值中。
|
||||
|
||||
## 处理Map数据类型
|
||||
|
||||
**第一种更加简洁的调用方法**
|
||||
|
||||
```go
|
||||
case reflect.Map:
|
||||
if subData, ok := value.(map[string]interface{}); ok {
|
||||
subResult := reflect.New(fieldType.Type).Elem()
|
||||
if err := parseMap(subResult, subData); err != nil {
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(subResult)
|
||||
}
|
||||
```
|
||||
|
||||
其中 subResult 使用 reflect.New 创建一个新的结构体对象,然后使用 Elem() 方法获取其指针所指向的值,最后传递给 parseMap 方法进行解析。这样可以避免对 reflect.MakeMap 的使用,更加简洁。
|
||||
|
||||
|
||||
**第二种实在原有的代码进行更改。**
|
||||
```go
|
||||
case reflect.Map:
|
||||
if subData, ok := value.(map[string]interface{}); ok {
|
||||
subResult := reflect.MakeMap(fieldValue.Type())
|
||||
for subKey, subValue := range subData {
|
||||
subElem := reflect.New(fieldType.Type.Elem())
|
||||
err := parseValue(subElem.Elem(), subValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subResult.SetMapIndex(reflect.ValueOf(subKey), subElem.Elem())
|
||||
}
|
||||
fieldValue.Set(subResult)
|
||||
}
|
||||
```
|
||||
|
||||
其中,subData 是一个 map[string]interface{} 类型的变量,表示一个嵌套的 JSON 对象;subResult 是一个 reflect.Value 类型的变量,表示一个 map 类型的变量的反射值;subKey 和 subValue 分别表示 subData 中的键和值,可以通过 range 循环遍历 subData。
|
||||
|
||||
在调用 parseValue 函数时,需要传入 subElem.Elem() 作为第一个参数,这是因为 subElem 表示一个指向 fieldType.Type.Elem() 类型变量的指针,而 parseValue 函数需要传入一个值类型的变量。所以需要通过 subElem.Elem() 获取到 fieldType.Type.Elem() 类型的变量。
|
@@ -1,112 +0,0 @@
|
||||
# jsonUtil
|
||||
|
||||
[English](README.md) | 简体中文
|
||||
|
||||
## 介绍
|
||||
|
||||
JsonToStruct 将 JSON 数据转换为 Go 结构。
|
||||
|
||||
**参数:**
|
||||
- jsonData:包含 JSON 数据的字符串。
|
||||
- val:指向要填充的结构变量的指针。
|
||||
|
||||
**返回:**
|
||||
- error:如果转换失败或发生错误,则返回相应的错误。如果成功,则返回 nil。
|
||||
|
||||
**功能:**
|
||||
- 检查 val 参数是否为非零指针类型,如果不是,则返回 ErrPoint。
|
||||
- 将 jsonData 解析为名为 data 的 map[string]any 变量。
|
||||
- 使用反射检索 val 指向的结构的值和类型。
|
||||
- 遍历结构的字段:
|
||||
- 检索字段的类型、名称和值。
|
||||
- 获取字段的 JSON 标签。
|
||||
- 如果数据中存在与 JSON 标签对应的键值对,则进行相应的处理:
|
||||
- 如果字段是原始类型(string、integer、float、boolean),则解析为对应类型的值。
|
||||
- 如果字段是结构体类型,则递归调用 JsonToStruct 函数将子结构体转换为 JSON。
|
||||
- 如果字段是映射类型,则使用 parseMap 函数将子映射转换为 JSON。
|
||||
- 如果字段是切片类型,则使用 parseSlice 函数将子切片转换为 JSON。
|
||||
- 如果字段是接口类型,则将值设置为 nil 或对应值。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
go get -u github.com/jefferyjob/go-easy-utils/v3/jsonx
|
||||
```
|
||||
|
||||
## 导入
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/jefferyjob/go-easy-utils/v3/jsonx"
|
||||
)
|
||||
```
|
||||
|
||||
## 方法
|
||||
|
||||
```go
|
||||
func JsonToStruct(jsonData string, val any) error
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
```go
|
||||
// name 使用了两个 json 标签
|
||||
// age 定义为 int,json 的值是 string
|
||||
// is_use 定义为 bool,json 的值是 int
|
||||
func TestDemo1(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "22",
|
||||
"is_use": "1"
|
||||
}`
|
||||
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
IsUse bool `json:"is_use"`
|
||||
}
|
||||
|
||||
if err := ToStruct(jsonData, &people); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v \n", people)
|
||||
// return
|
||||
// {Name:make Age:22 IsUse:true}
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// 结构嵌套和切片嵌套处理
|
||||
func TestJsonToStructDemo2(t *testing.T) {
|
||||
type Address struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
}
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Address Address `json:"address"`
|
||||
Interests []string `json:"interests"`
|
||||
}
|
||||
|
||||
jsonData := `{
|
||||
"name": "Bob",
|
||||
"age": "25",
|
||||
"address": {
|
||||
"city": "Shanghai",
|
||||
"country": "China"
|
||||
},
|
||||
"interests": ["reading", "swimming"]
|
||||
}`
|
||||
|
||||
var person Person
|
||||
err := ToStruct(jsonData, &person)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v \n", person)
|
||||
// {Name:Bob Age:25 Address:{City:Shanghai Country:China} Interests:[reading swimming]}
|
||||
}
|
||||
```
|
112
jsonx/README.md
112
jsonx/README.md
@@ -1,112 +0,0 @@
|
||||
# jsonx
|
||||
|
||||
English | [简体中文](README.cn.md)
|
||||
|
||||
## Introduce
|
||||
|
||||
JsonToStruct converts JSON data to a Go structure.
|
||||
|
||||
**Parameters:**
|
||||
- jsonData: A string containing the JSON data.
|
||||
- val: A pointer to the structure variable to be filled.
|
||||
|
||||
**Returns:**
|
||||
- error: If conversion fails or an error occurs, the corresponding error is returned. If successful, nil is returned.
|
||||
|
||||
**Functionality:**
|
||||
- Checks if the val parameter is a non-nil pointer type, returning ErrPoint if it is not.
|
||||
- Parses jsonData into a map[string]any variable called data.
|
||||
- Retrieves the value and type of the structure pointed to by val using reflection.
|
||||
- Iterates through the fields of the structure:
|
||||
- Retrieves the field's type, name, and value.
|
||||
- Gets the JSON tag for the field.
|
||||
- Performs the appropriate handling if a key-value pair corresponding to the JSON tag exists in data:
|
||||
- If the field is a primitive type (string, integer, float, boolean), parses it into the corresponding type's value.
|
||||
- If the field is a struct type, recursively calls the JsonToStruct function to convert the sub-structure to JSON.
|
||||
- If the field is a map type, uses the parseMap function to convert the sub-map to JSON.
|
||||
- If the field is a slice type, uses the parseSlice function to convert the sub-slice to JSON.
|
||||
- If the field is an interface type, sets the value to nil or the corresponding value.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get -u github.com/jefferyjob/go-easy-utils/v3/jsonx
|
||||
```
|
||||
|
||||
## Import
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/jefferyjob/go-easy-utils/v3/jsonx"
|
||||
)
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
```go
|
||||
func ToStruct(jsonData string, val any) error
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
```go
|
||||
// name uses two json tags
|
||||
// age is defined as int, and the value of json is string
|
||||
// is_use is defined as bool, the value of json is int
|
||||
func TestDemo1(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "22",
|
||||
"is_use": "1"
|
||||
}`
|
||||
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
IsUse bool `json:"is_use"`
|
||||
}
|
||||
|
||||
if err := ToStruct(jsonData, &people); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v \n", people)
|
||||
// return
|
||||
// {Name:make Age:22 IsUse:true}
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// Structure nesting and slice nesting processing
|
||||
func TestJsonToStructDemo2(t *testing.T) {
|
||||
type Address struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
}
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Address Address `json:"address"`
|
||||
Interests []string `json:"interests"`
|
||||
}
|
||||
|
||||
jsonData := `{
|
||||
"name": "Bob",
|
||||
"age": "25",
|
||||
"address": {
|
||||
"city": "Shanghai",
|
||||
"country": "China"
|
||||
},
|
||||
"interests": ["reading", "swimming"]
|
||||
}`
|
||||
|
||||
var person Person
|
||||
err := ToStruct(jsonData, &person)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v \n", person)
|
||||
// {Name:Bob Age:25 Address:{City:Shanghai Country:China} Interests:[reading swimming]}
|
||||
}
|
||||
```
|
@@ -2,17 +2,18 @@ package jsonx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrPoint 不是指针类型
|
||||
// ErrPoint = errors.New("the argument to Result must be a non-nil pointer")
|
||||
// // ErrNotMap 不是Map类型
|
||||
// ErrNotMap = errors.New("cannot parse map, value is not a map")
|
||||
// // ErrNotSlice 不是Slice类型
|
||||
// ErrNotSlice = errors.New("cannot parse slice, value is not a slice")
|
||||
// // ErrSyntax 指示值不具有目标类型的正确语法
|
||||
// ErrSyntax = strconv.ErrSyntax
|
||||
ErrPoint = errors.New("the argument to Result must be a non-nil pointer")
|
||||
// ErrNotMap 不是Map类型
|
||||
ErrNotMap = errors.New("cannot parse map, value is not a map")
|
||||
// ErrNotSlice 不是Slice类型
|
||||
ErrNotSlice = errors.New("cannot parse slice, value is not a slice")
|
||||
// ErrSyntax 指示值不具有目标类型的正确语法
|
||||
ErrSyntax = strconv.ErrSyntax
|
||||
// ErrUnsupported 不支持的类型
|
||||
ErrUnsupported = errors.New("unsupported type")
|
||||
)
|
||||
|
@@ -1,103 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func parseMap(value reflect.Value, data map[string]any) error {
|
||||
if value.Kind() != reflect.Map {
|
||||
return ErrNotMap
|
||||
}
|
||||
|
||||
valueType := value.Type().Elem()
|
||||
newMap := reflect.MakeMapWithSize(value.Type(), len(data))
|
||||
|
||||
for key, val := range data {
|
||||
newKey := reflect.ValueOf(key)
|
||||
|
||||
if valueType.Kind() == reflect.Interface {
|
||||
newMap.SetMapIndex(newKey, reflect.ValueOf(val))
|
||||
} else if valueType.Kind() == reflect.Map {
|
||||
newElem := reflect.New(valueType).Elem()
|
||||
if err := parseMap(newElem, val.(map[string]any)); err != nil {
|
||||
return err
|
||||
}
|
||||
newMap.SetMapIndex(newKey, newElem)
|
||||
} else {
|
||||
newVal := reflect.New(valueType).Elem()
|
||||
if err := parseValue(newVal, val); err != nil {
|
||||
return err
|
||||
}
|
||||
newMap.SetMapIndex(newKey, newVal)
|
||||
}
|
||||
}
|
||||
|
||||
value.Set(newMap)
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseValue(fieldVal reflect.Value, item any) error {
|
||||
switch fieldVal.Kind() {
|
||||
case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.Bool:
|
||||
if err := parsePrimitiveValue(fieldVal, item); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Struct:
|
||||
if subData, ok := item.(map[string]any); ok {
|
||||
if err := ToStruct(convertToJSONString(subData), fieldVal.Addr().Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("unexpected value type for struct: %T", item)
|
||||
}
|
||||
case reflect.Slice:
|
||||
if arr, ok := item.([]any); ok {
|
||||
elemType := fieldVal.Type().Elem()
|
||||
sliceVal := reflect.MakeSlice(fieldVal.Type(), len(arr), len(arr))
|
||||
for i, elem := range arr {
|
||||
elemVal := reflect.New(elemType).Elem()
|
||||
if err := parseValue(elemVal, elem); err != nil {
|
||||
return err
|
||||
}
|
||||
sliceVal.Index(i).Set(elemVal)
|
||||
}
|
||||
fieldVal.Set(sliceVal)
|
||||
} else {
|
||||
return fmt.Errorf("unexpected value type for slice: %T", item)
|
||||
}
|
||||
case reflect.Map:
|
||||
if mapData, ok := item.(map[string]any); ok {
|
||||
mapType := fieldVal.Type()
|
||||
if fieldVal.IsNil() {
|
||||
fieldVal.Set(reflect.MakeMap(mapType))
|
||||
}
|
||||
elemType := mapType.Elem()
|
||||
mapVal := fieldVal
|
||||
for k, v := range mapData {
|
||||
keyVal := reflect.New(mapType.Key()).Elem()
|
||||
if err := parseValue(keyVal, k); err != nil {
|
||||
return err
|
||||
}
|
||||
elemVal := reflect.New(elemType).Elem()
|
||||
if err := parseValue(elemVal, v); err != nil {
|
||||
return err
|
||||
}
|
||||
mapVal.SetMapIndex(keyVal, elemVal)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("unexpected value type for map: %T", item)
|
||||
}
|
||||
case reflect.Interface:
|
||||
if item == nil {
|
||||
fieldVal.Set(reflect.Zero(fieldVal.Type()))
|
||||
} else {
|
||||
fieldVal.Set(reflect.ValueOf(item))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported kind: %s", fieldVal.Kind())
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -1,91 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseMap(t *testing.T) {
|
||||
type TestData struct {
|
||||
Foo string
|
||||
Bar int
|
||||
}
|
||||
|
||||
// 包含映射类型的测试用例
|
||||
testData := map[string]any{
|
||||
"Foo": "hello",
|
||||
"Bar": 42,
|
||||
}
|
||||
|
||||
var result map[string]any
|
||||
err := parseMap(reflect.ValueOf(&result).Elem(), testData)
|
||||
if err != nil {
|
||||
t.Errorf("parseMap 失败: %s", err)
|
||||
}
|
||||
|
||||
// 检查值是否被正确解析
|
||||
expectedResult := map[string]any{"Foo": "hello", "Bar": 42}
|
||||
if !reflect.DeepEqual(result, expectedResult) {
|
||||
t.Errorf("parseMap 结果不匹配:\n期望值: %v\n实际值: %v", expectedResult, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseValue(t *testing.T) {
|
||||
// 测试解析原始类型
|
||||
var intValue int
|
||||
err := parseValue(reflect.ValueOf(&intValue).Elem(), 42)
|
||||
if err != nil {
|
||||
t.Errorf("parseValue 失败: %s", err)
|
||||
}
|
||||
if intValue != 42 {
|
||||
t.Errorf("parseValue 结果不匹配: 期望值 42,实际值 %d", intValue)
|
||||
}
|
||||
|
||||
// 测试解析结构体
|
||||
type TestStruct struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
var structValue TestStruct
|
||||
err = parseValue(reflect.ValueOf(&structValue).Elem(), map[string]any{"Name": "John", "Age": 30})
|
||||
if err != nil {
|
||||
t.Errorf("parseValue 失败: %s", err)
|
||||
}
|
||||
|
||||
expectedStructValue := TestStruct{"John", 30}
|
||||
if !reflect.DeepEqual(structValue, expectedStructValue) {
|
||||
t.Errorf("parseValue 结果不匹配:\n期望值: %v\n实际值: %v", expectedStructValue, structValue)
|
||||
}
|
||||
|
||||
// 测试解析切片
|
||||
var sliceValue []int
|
||||
err = parseValue(reflect.ValueOf(&sliceValue).Elem(), []any{1, 2, 3})
|
||||
if err != nil {
|
||||
t.Errorf("parseValue 失败: %s", err)
|
||||
}
|
||||
|
||||
expectedSliceValue := []int{1, 2, 3}
|
||||
if !reflect.DeepEqual(sliceValue, expectedSliceValue) {
|
||||
t.Errorf("parseValue 结果不匹配:\n期望值: %v\n实际值: %v", expectedSliceValue, sliceValue)
|
||||
}
|
||||
|
||||
// 测试解析接口
|
||||
var interfaceValue interface{}
|
||||
err = parseValue(reflect.ValueOf(&interfaceValue).Elem(), "test")
|
||||
if err != nil {
|
||||
t.Errorf("parseValue 失败: %s", err)
|
||||
}
|
||||
|
||||
expectedInterfaceValue := "test"
|
||||
if !reflect.DeepEqual(interfaceValue, expectedInterfaceValue) {
|
||||
t.Errorf("parseValue 结果不匹配:\n期望值: %v\n实际值: %v", expectedInterfaceValue, interfaceValue)
|
||||
}
|
||||
|
||||
// 测试不支持的类型
|
||||
var unsupportedValue complex64
|
||||
err = parseValue(reflect.ValueOf(&unsupportedValue).Elem(), 3.14)
|
||||
if err == nil {
|
||||
t.Errorf("parseValue 对于不支持的类型应该失败")
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 原始数据类型转换支持
|
||||
// 将数据转为Struct指定的类型
|
||||
func parsePrimitiveValue(fieldVal reflect.Value, v any) error {
|
||||
switch fieldVal.Kind() {
|
||||
case reflect.String:
|
||||
fieldVal.SetString(toStringReflect(v))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n, err := toInt64Reflect(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldVal.SetInt(n)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
n, err := toUint64Reflect(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldVal.SetUint(uint64(n))
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n, err := toFloat64Reflect(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldVal.SetFloat(n)
|
||||
case reflect.Bool:
|
||||
fieldVal.SetBool(toBoolReflect(v))
|
||||
default:
|
||||
return fmt.Errorf("unsupported kind: %s", fieldVal.Kind())
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParsePrimitiveValue(t *testing.T) {
|
||||
// 测试 reflect.String 类型的情况
|
||||
strFieldVal := reflect.ValueOf(new(string)).Elem()
|
||||
err := parsePrimitiveValue(strFieldVal, "hello")
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing string value: %v", err)
|
||||
}
|
||||
if strFieldVal.String() != "hello" {
|
||||
t.Errorf("Expected %q, got %q", "hello", strFieldVal.String())
|
||||
}
|
||||
err = parsePrimitiveValue(strFieldVal, 123)
|
||||
if err != nil {
|
||||
t.Error("Expected error for parsing int value as string")
|
||||
}
|
||||
// 测试 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64 类型的情况
|
||||
intFieldVal := reflect.ValueOf(new(int64)).Elem()
|
||||
err = parsePrimitiveValue(intFieldVal, "123")
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing int value: %v", err)
|
||||
}
|
||||
if intFieldVal.Int() != 123 {
|
||||
t.Errorf("Expected %d, got %d", 123, intFieldVal.Int())
|
||||
}
|
||||
err = parsePrimitiveValue(intFieldVal, "abc")
|
||||
if err == nil {
|
||||
t.Error("Expected error for parsing non-int value as int")
|
||||
}
|
||||
|
||||
// 测试 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64 类型的情况
|
||||
uintFieldVal := reflect.ValueOf(new(uint64)).Elem()
|
||||
err = parsePrimitiveValue(uintFieldVal, "123")
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing uint value: %v", err)
|
||||
}
|
||||
if uintFieldVal.Uint() != 123 {
|
||||
t.Errorf("Expected %d, got %d", 123, uintFieldVal.Uint())
|
||||
}
|
||||
err = parsePrimitiveValue(uintFieldVal, 123)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error: %v", err)
|
||||
}
|
||||
|
||||
// 测试 reflect.Float32, reflect.Float64 类型的情况
|
||||
floatFieldVal := reflect.ValueOf(new(float64)).Elem()
|
||||
err = parsePrimitiveValue(floatFieldVal, "3.14")
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing float value: %v", err)
|
||||
}
|
||||
if floatFieldVal.Float() != 3.14 {
|
||||
t.Errorf("Expected %f, got %f", 3.14, floatFieldVal.Float())
|
||||
}
|
||||
err = parsePrimitiveValue(floatFieldVal, "abc")
|
||||
if err == nil {
|
||||
t.Error("Expected error for parsing non-float value as float")
|
||||
}
|
||||
|
||||
// 测试 reflect.Bool 类型的情况
|
||||
boolFieldVal := reflect.ValueOf(new(bool)).Elem()
|
||||
err = parsePrimitiveValue(boolFieldVal, true)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing bool value: %v", err)
|
||||
}
|
||||
if boolFieldVal.Bool() != true {
|
||||
t.Errorf("Expected %t, got %t", true, boolFieldVal.Bool())
|
||||
}
|
||||
err = parsePrimitiveValue(boolFieldVal, "abc")
|
||||
if err != nil {
|
||||
t.Error("Expected error for parsing non-bool value as bool")
|
||||
}
|
||||
|
||||
// 测试不支持的类型的情况
|
||||
unsupportedFieldVal := reflect.ValueOf(new([]string)).Elem()
|
||||
err = parsePrimitiveValue(unsupportedFieldVal, "abc")
|
||||
if err == nil {
|
||||
t.Error("Expected error for unsupported kind")
|
||||
}
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func parseSlice(fieldValue reflect.Value, subData []any) error {
|
||||
if fieldValue.Kind() != reflect.Slice {
|
||||
return ErrNotSlice
|
||||
}
|
||||
|
||||
// 获取切片元素类型
|
||||
elemType := fieldValue.Type().Elem()
|
||||
|
||||
// 创建一个与目标字段相同类型的新切片
|
||||
slice := reflect.MakeSlice(fieldValue.Type(), 0, len(subData))
|
||||
|
||||
// 迭代 subData 切片的元素
|
||||
for _, item := range subData {
|
||||
// 创建 slice 元素类型的新元素
|
||||
elem := reflect.New(elemType).Elem()
|
||||
|
||||
// 如果元素类型是结构体,则递归调用 JsonToStruct
|
||||
if elem.Kind() == reflect.Struct {
|
||||
// 将项目转换为 JSON 字符串
|
||||
jsonData, err := json.Marshal(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 调用 ToStruct 将 JSON 字符串解析为 struct 元素
|
||||
err = ToStruct(string(jsonData), elem.Addr().Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if elemType.Kind() == reflect.Interface {
|
||||
if item == nil {
|
||||
elem.Set(reflect.Zero(elemType))
|
||||
} else {
|
||||
elem.Set(reflect.ValueOf(item))
|
||||
}
|
||||
} else {
|
||||
// 否则,将项目转换为适当的类型并设置元素值
|
||||
switch elem.Kind() {
|
||||
case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.Bool:
|
||||
err := parsePrimitiveValue(elem, item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported slice element type: %s", elemType.String())
|
||||
}
|
||||
}
|
||||
|
||||
slice = reflect.Append(slice, elem) // 将元素附加到切片
|
||||
}
|
||||
|
||||
fieldValue.Set(slice) // 将切片值设置为目标字段
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ExampleStruct struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
func TestParseSlice(t *testing.T) {
|
||||
var slice []any
|
||||
|
||||
// 添加元素到切片
|
||||
slice = append(slice, "hello")
|
||||
slice = append(slice, "world")
|
||||
|
||||
// 创建一个新的切片值
|
||||
sliceValue := reflect.ValueOf(&[]string{}).Elem()
|
||||
|
||||
// 解析切片
|
||||
err := parseSlice(sliceValue, slice)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but got %s", err.Error())
|
||||
}
|
||||
|
||||
// 检查解析的切片是否与预期相等
|
||||
expectedSlice := []string{"hello", "world"}
|
||||
actualSlice := sliceValue.Interface().([]string)
|
||||
if !reflect.DeepEqual(expectedSlice, actualSlice) {
|
||||
t.Errorf("expected %v, but got %v", expectedSlice, actualSlice)
|
||||
}
|
||||
|
||||
// 测试解析结构体切片
|
||||
var structSlice []any
|
||||
structSlice = append(structSlice, ExampleStruct{"Tom", 30})
|
||||
structSlice = append(structSlice, ExampleStruct{"Jerry", 25})
|
||||
|
||||
// 创建一个新的切片值
|
||||
structSliceValue := reflect.ValueOf(&[]ExampleStruct{}).Elem()
|
||||
|
||||
// 解析切片
|
||||
err = parseSlice(structSliceValue, structSlice)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but got %s", err.Error())
|
||||
}
|
||||
|
||||
// 检查解析的切片是否与预期相等
|
||||
expectedStructSlice := []ExampleStruct{{"Tom", 30}, {"Jerry", 25}}
|
||||
actualStructSlice := structSliceValue.Interface().([]ExampleStruct)
|
||||
if !reflect.DeepEqual(expectedStructSlice, actualStructSlice) {
|
||||
t.Errorf("expected %v, but got %v", expectedStructSlice, actualStructSlice)
|
||||
}
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func toBoolReflect(i any) bool {
|
||||
if i == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(i)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return false
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
return v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() != 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() != 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() != 0
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return v.Complex() != 0
|
||||
case reflect.String:
|
||||
val := v.String()
|
||||
if val == "true" {
|
||||
return true
|
||||
} else if val == "false" {
|
||||
return false
|
||||
}
|
||||
return val != ""
|
||||
// case reflect.Ptr, reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Slice:
|
||||
// return !v.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToBool(t *testing.T) {
|
||||
var iPtr = 90
|
||||
var tests = []struct {
|
||||
name string
|
||||
input any
|
||||
want bool
|
||||
}{
|
||||
{"布尔真", true, true},
|
||||
{"布尔假", false, false},
|
||||
{"负整数", int(-1), true},
|
||||
{"正整数", int(1), true},
|
||||
{"零整数", int(0), false},
|
||||
{"正int8", int8(1), true},
|
||||
{"零int8", int8(0), false},
|
||||
{"正int16", int16(1), true},
|
||||
{"零int16", int16(0), false},
|
||||
{"正int32", int32(1), true},
|
||||
{"零int32", int32(0), false},
|
||||
{"正int64", int64(1), true},
|
||||
{"零int64", int64(0), false},
|
||||
{"正uint", uint(1), true},
|
||||
{"零uint", uint(0), false},
|
||||
{"正uint8", uint8(1), true},
|
||||
{"零uint8", uint8(0), false},
|
||||
{"正uint16", uint16(1), true},
|
||||
{"零uint16", uint16(0), false},
|
||||
{"正uint32", uint32(1), true},
|
||||
{"零uint32", uint32(0), false},
|
||||
{"正uint64", uint64(1), true},
|
||||
{"零uint64", uint64(0), false},
|
||||
{"浮点1.0", float32(1.0), true},
|
||||
{"浮点0.0", float32(0.0), false},
|
||||
{"双精1.0", float64(1.0), true},
|
||||
{"双精0.0", float64(0.0), false},
|
||||
{"字符串", "abc", true},
|
||||
{"字符串真", "true", true},
|
||||
{"字符串假", "false", false},
|
||||
{"空字符串", "", false},
|
||||
{"空值", nil, false},
|
||||
{"非空指针", &iPtr, true},
|
||||
{"复数1+1i", complex64(1 + 1i), true},
|
||||
{"复数0+0i", complex64(0 + 0i), false},
|
||||
{"双复1+1i", complex128(1 + 1i), true},
|
||||
{"双复0+0i", complex128(0 + 0i), false},
|
||||
{"空指针", (*int)(nil), false},
|
||||
{"通道", make(chan int), false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res := toBoolReflect(tc.input)
|
||||
assert.Equal(t, tc.want, res)
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func toFloat64Reflect(i any) (float64, error) {
|
||||
if i == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(i)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return 0, nil
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float(), nil
|
||||
case reflect.String:
|
||||
if v.String() == "" {
|
||||
return 0, nil
|
||||
}
|
||||
floatValue, err := strconv.ParseFloat(v.String(), 64)
|
||||
if err != nil {
|
||||
return 0, ErrSyntax
|
||||
}
|
||||
return floatValue, nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return float64(v.Int()), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return float64(v.Uint()), nil
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return real(v.Complex()), nil
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
return 1, nil
|
||||
} else {
|
||||
return 0, nil
|
||||
}
|
||||
// case reflect.Ptr, reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Slice:
|
||||
// return 0, nil
|
||||
default:
|
||||
return 0, ErrType
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToFloat64(t *testing.T) {
|
||||
var iPtr = 90
|
||||
testCases := []struct {
|
||||
name string
|
||||
value any
|
||||
expected float64
|
||||
expectedErr error
|
||||
}{
|
||||
{"空值", nil, 0, nil},
|
||||
{"浮点数", float32(123.5), 123.5, nil},
|
||||
{"字符串数", "123.456", 123.456, nil},
|
||||
{"无符整型", uint(123), 123, nil},
|
||||
{"无符uint8", uint8(123), 123, nil},
|
||||
{"无符uint16", uint16(123), 123, nil},
|
||||
{"无符uint32", uint32(123), 123, nil},
|
||||
{"无符uint64", uint64(123), 123, nil},
|
||||
{"有符整型", int(123), 123, nil},
|
||||
{"有符int8", int8(123), 123, nil},
|
||||
{"有符int16", int16(123), 123, nil},
|
||||
{"有符int32", int32(123), 123, nil},
|
||||
{"有符int64", int64(123), 123, nil},
|
||||
{"复数64", complex64(1 + 2i), 1, nil},
|
||||
{"复数128", complex128(1 + 2i), 1, nil},
|
||||
{"布尔真", true, 1, nil},
|
||||
{"布尔假", false, 0, nil},
|
||||
{"空布尔指针", (*bool)(nil), 0, nil},
|
||||
{"非空指针", &iPtr, 90, nil},
|
||||
{"通道", make(chan int), 0, ErrType},
|
||||
{"无效字符串", "abc", 0, ErrSyntax},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := toFloat64Reflect(tc.value)
|
||||
assert.Equal(t, tc.expectedErr, err)
|
||||
assert.Equal(t, tc.expected, res)
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func toInt64Reflect(i any) (int64, error) {
|
||||
if i == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(i)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return 0, nil
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return int64(v.Float()), nil
|
||||
case reflect.String:
|
||||
if v.String() == "" {
|
||||
return 0, nil
|
||||
}
|
||||
intValue, err := strconv.ParseInt(v.String(), 10, 64)
|
||||
if err != nil {
|
||||
return 0, ErrSyntax
|
||||
}
|
||||
return intValue, nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int(), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return int64(v.Uint()), nil
|
||||
case reflect.Complex64:
|
||||
return int64(real(v.Complex())), nil
|
||||
case reflect.Complex128:
|
||||
return int64(real(v.Complex())), nil
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
return 1, nil
|
||||
} else {
|
||||
return 0, nil
|
||||
}
|
||||
default:
|
||||
return 0, ErrType
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAnyToInt64(t *testing.T) {
|
||||
var iPtr = 90
|
||||
testCases := []struct {
|
||||
name string
|
||||
input any
|
||||
expected int64
|
||||
err error
|
||||
}{
|
||||
// 测试整数输入
|
||||
{name: "number", input: 42, expected: 42, err: nil},
|
||||
{name: "int", input: int(42), expected: 42, err: nil},
|
||||
{name: "int64", input: int64(42), expected: 42, err: nil},
|
||||
{name: "int32", input: int32(42), expected: 42, err: nil},
|
||||
{name: "int", input: int(42), expected: 42, err: nil},
|
||||
{name: "int64", input: uint64(42), expected: 42, err: nil},
|
||||
{name: "int32", input: uint32(42), expected: 42, err: nil},
|
||||
{name: "uint", input: uint(42), expected: 42, err: nil},
|
||||
|
||||
// 测试浮点数输入
|
||||
{name: "float64", input: float64(42.0), expected: 42, err: nil},
|
||||
{name: "float32", input: float32(42.0), expected: 42, err: nil},
|
||||
{name: "float64_小数点", input: float64(42.5), expected: 42, err: nil},
|
||||
|
||||
// 测试非数值类型
|
||||
{name: "string", input: "rand string", expected: 0, err: ErrSyntax},
|
||||
{name: "nil", input: nil, expected: 0, err: nil},
|
||||
|
||||
// 布尔
|
||||
{name: "true", input: true, expected: 1, err: nil},
|
||||
{name: "false", input: false, expected: 0, err: nil},
|
||||
|
||||
// 空指针
|
||||
{name: "nil point", input: (*int)(nil), expected: 0, err: nil},
|
||||
{name: "point", input: &iPtr, expected: 90, err: nil},
|
||||
|
||||
// complex
|
||||
{name: "complex128", input: complex(3.14, 1.59), expected: 3, err: nil},
|
||||
{name: "complex64", input: complex(float32(2.71), float32(1.41)), expected: 2, err: nil},
|
||||
|
||||
// 其他
|
||||
{name: "struct", input: struct{ Name string }{Name: "test"}, expected: 0, err: ErrType},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := toInt64Reflect(tc.input)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.expected, res)
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func toStringReflect(i any) string {
|
||||
if i == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(i)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return ""
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
return v.String()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(v.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return strconv.FormatUint(v.Uint(), 10)
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(v.Float(), 'f', -1, 32)
|
||||
case reflect.Float64:
|
||||
return strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
||||
case reflect.Complex64:
|
||||
return fmt.Sprintf("(%g+%gi)", real(v.Complex()), imag(v.Complex()))
|
||||
case reflect.Complex128:
|
||||
return fmt.Sprintf("(%g+%gi)", real(v.Complex()), imag(v.Complex()))
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(v.Bool())
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToString(t *testing.T) {
|
||||
var iPar = "point"
|
||||
tests := []struct {
|
||||
name string
|
||||
value any
|
||||
want string
|
||||
}{
|
||||
{"nil", nil, ""},
|
||||
{"string", "hello", "hello"},
|
||||
{"int", 42, "42"},
|
||||
{"int8", int8(42), "42"},
|
||||
{"int16", int16(42), "42"},
|
||||
{"int32", int32(42), "42"},
|
||||
{"int64", int64(42), "42"},
|
||||
{"uint", uint(42), "42"},
|
||||
{"uint8", uint8(42), "42"},
|
||||
{"uint16", uint16(42), "42"},
|
||||
{"uint32", uint32(42), "42"},
|
||||
{"uint64", uint64(42), "42"},
|
||||
{"float32", float32(3.14159), "3.14159"},
|
||||
{"float64", 3.14159, "3.14159"},
|
||||
{"bool-true", true, "true"},
|
||||
{"bool-false", false, "false"},
|
||||
{"point", &iPar, "point"},
|
||||
{"complex64", complex64(1 + 2i), "(1+2i)"},
|
||||
{"complex128", complex128(3 + 4i), "(3+4i)"},
|
||||
{"chan", make(chan int), ""},
|
||||
{"int nil", (*int)(nil), ""},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := toStringReflect(tt.value)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,120 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ToStruct converts JSON data to a Go structure.
|
||||
// Parameters:
|
||||
//
|
||||
// jsonData: A string containing the JSON data.
|
||||
// val: A pointer to the structure variable to be filled.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// error: If conversion fails or an error occurs, the corresponding error is returned. If successful, nil is returned.
|
||||
//
|
||||
// Functionality:
|
||||
//
|
||||
// Checks if the val parameter is a non-nil pointer type, returning ErrPoint if it is not.
|
||||
// Parses jsonData into a map[string]any variable called data.
|
||||
// Retrieve the value and type of the structure pointed to by val using reflection.
|
||||
// Iterates through the fields of the structure:
|
||||
// Retrieves the field's type, name, and value.
|
||||
// Get the JSON tag for the field.
|
||||
// Performs the appropriate handling if a key-value pair corresponding to the JSON tag exists in data:
|
||||
// If the field is a primitive type (string, integer, float, boolean), parses it into the corresponding type's value.
|
||||
// If the field is a struct type, recursively calls the JsonToStruct function to convert the sub-structure to JSON.
|
||||
// If the field is a map type, uses the parseMap function to convert the sub-map to JSON.
|
||||
// If the field is a slice type, uses the parseSlice function to convert the sub-slice to JSON.
|
||||
// If the field is an interface type, sets the value to nil or the corresponding value.
|
||||
func ToStruct(jsonData string, val any) error {
|
||||
if reflect.ValueOf(val).Kind() != reflect.Pointer || reflect.ValueOf(val).IsNil() {
|
||||
return ErrPoint
|
||||
}
|
||||
|
||||
var data map[string]any
|
||||
err := json.Unmarshal([]byte(jsonData), &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resultValue := reflect.ValueOf(val).Elem()
|
||||
resultType := resultValue.Type()
|
||||
|
||||
for i := 0; i < resultType.NumField(); i++ {
|
||||
fieldType := resultType.Field(i)
|
||||
fieldName := fieldType.Name
|
||||
fieldValue := resultValue.FieldByName(fieldName)
|
||||
|
||||
// 获取json的tag
|
||||
jsonTag := getJsonTag(fieldType, fieldName)
|
||||
|
||||
value, ok := data[jsonTag]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
switch fieldValue.Kind() {
|
||||
case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.Bool:
|
||||
if err := parsePrimitiveValue(fieldValue, value); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Struct:
|
||||
if subData, ok := value.(map[string]any); ok {
|
||||
subResult := reflect.New(fieldValue.Type())
|
||||
err := ToStruct(convertToJSONString(subData), subResult.Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(subResult.Elem())
|
||||
}
|
||||
case reflect.Map:
|
||||
if subData, ok := value.(map[string]any); ok {
|
||||
subResult := reflect.New(fieldType.Type).Elem()
|
||||
if err := parseMap(subResult, subData); err != nil {
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(subResult)
|
||||
}
|
||||
case reflect.Slice:
|
||||
if subData, ok := value.([]any); ok {
|
||||
if err := parseSlice(fieldValue, subData); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("unexpected value type for slice: %T", value)
|
||||
}
|
||||
case reflect.Interface:
|
||||
if value == nil {
|
||||
fieldValue.Set(reflect.Zero(fieldType.Type))
|
||||
} else {
|
||||
fieldValue.Set(reflect.ValueOf(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 从json的tag标签中取出定义字段
|
||||
func getJsonTag(fieldType reflect.StructField, fieldName string) string {
|
||||
jsonTag := fieldType.Tag.Get("json")
|
||||
if jsonTag == "" {
|
||||
jsonTag = fieldName
|
||||
} else {
|
||||
if commaIndex := strings.Index(jsonTag, ","); commaIndex != -1 {
|
||||
jsonTag = jsonTag[:commaIndex]
|
||||
}
|
||||
}
|
||||
return jsonTag
|
||||
}
|
||||
|
||||
func convertToJSONString(data map[string]any) string {
|
||||
jsonBytes, _ := json.Marshal(data)
|
||||
return string(jsonBytes)
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleToStruct() {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "22",
|
||||
"is_use": "1"
|
||||
}`
|
||||
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
IsUse bool `json:"is_use"`
|
||||
}
|
||||
|
||||
if err := ToStruct(jsonData, &people); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v", people)
|
||||
|
||||
// Output:
|
||||
// {Name:make Age:22 IsUse:true}
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJsonToStructMap1(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"uid": 43015653,
|
||||
"foll": {
|
||||
"43015653": true,
|
||||
"43015666": false
|
||||
},
|
||||
"followed": {
|
||||
"friendRed": {
|
||||
"43015653": true,
|
||||
"43015666": false
|
||||
},
|
||||
"friendWhite": {
|
||||
"43015653": true,
|
||||
"43015666": false
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
var target struct {
|
||||
Uid int `json:"uid"`
|
||||
Foll map[string]bool `json:"foll"`
|
||||
Followed map[string]map[string]bool `json:"followed"`
|
||||
}
|
||||
|
||||
err := ToStruct(data, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonToStructMap2(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"uid": 43015653,
|
||||
"foll": {
|
||||
"boy": {
|
||||
"t1": "v1",
|
||||
"t2": "v2"
|
||||
},
|
||||
"girl": {
|
||||
"t1": "v1",
|
||||
"t2": "v2"
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
type Val struct {
|
||||
T1 string `json:"t1"`
|
||||
T2 string `json:"t2"`
|
||||
}
|
||||
|
||||
var target struct {
|
||||
Uid int `json:"uid"`
|
||||
Foll map[string]Val `json:"foll"`
|
||||
}
|
||||
|
||||
err := ToStruct(data, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJsonToStructSlice1(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"uid": 43015653,
|
||||
"fids": ["43015653", 43015666]
|
||||
}
|
||||
`
|
||||
var target struct {
|
||||
Uid int `json:"uid"`
|
||||
Fids []string `json:"fids"`
|
||||
}
|
||||
|
||||
err := ToStruct(data, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
@@ -1,629 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// name uses two json tags
|
||||
// age is defined as int, and the value of json is string
|
||||
// is_use is defined as bool, the value of json is int
|
||||
func TestDemo1(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "22",
|
||||
"is_use": "1"
|
||||
}`
|
||||
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
IsUse bool `json:"is_use"`
|
||||
}
|
||||
|
||||
if err := ToStruct(jsonData, &people); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v \n", people)
|
||||
// return
|
||||
// {Name:make Age:22 IsUse:true}
|
||||
}
|
||||
|
||||
// Structure nesting and slice nesting processing
|
||||
func TestJsonToStructDemo2(t *testing.T) {
|
||||
type Address struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
}
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Address Address `json:"address"`
|
||||
Interests []string `json:"interests"`
|
||||
}
|
||||
|
||||
jsonData2 := `{
|
||||
"name": "Bob",
|
||||
"age": "25",
|
||||
"address": {
|
||||
"city": "Shanghai",
|
||||
"country": "China"
|
||||
},
|
||||
"interests": ["reading", "swimming"]
|
||||
}`
|
||||
|
||||
var person Person
|
||||
err := ToStruct(jsonData2, &person)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v \n", person)
|
||||
// {Name:Bob Age:25 Address:{City:Shanghai Country:China} Interests:[reading swimming]}
|
||||
}
|
||||
|
||||
func BenchmarkJsonUnmarshal(b *testing.B) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": 22,
|
||||
"is_use": true
|
||||
}`
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
IsUse bool `json:"is_use"`
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := json.Unmarshal([]byte(jsonData), &people)
|
||||
if err != nil {
|
||||
fmt.Println("err:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkJsonToStruct(b *testing.B) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "22",
|
||||
"is_use": true
|
||||
}`
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
IsUse bool `json:"is_use"`
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := ToStruct(jsonData, &people)
|
||||
if err != nil {
|
||||
fmt.Println("err:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 非法验证:非法的json字符串
|
||||
func TestJsonToStructErrJson(t *testing.T) {
|
||||
jsonData := `{"name":}`
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
var people People
|
||||
err := ToStruct(jsonData, &people)
|
||||
if err == nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 非法验证:非指针的result
|
||||
func TestJsonToStructErrResult(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "22",
|
||||
"is_use": "1"
|
||||
}`
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
IsUse bool `json:"is_use"`
|
||||
}
|
||||
err := ToStruct(jsonData, people)
|
||||
if err == nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 合法验证:空数据
|
||||
func TestJsonToStructEmptyValue(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "",
|
||||
"source": "",
|
||||
"num": "",
|
||||
"status": ""
|
||||
}`
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
Source uint `json:"source"`
|
||||
Num float64 `json:"num"`
|
||||
Status bool `json:"status"`
|
||||
}
|
||||
err := ToStruct(jsonData, &people)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 非法验证:非法的int
|
||||
func TestJsonToStructErrInt(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "test abc"
|
||||
}`
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
err := ToStruct(jsonData, people)
|
||||
if err == nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 非法验证:非法的uint
|
||||
func TestJsonToStructErrUint(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "test abc"
|
||||
}`
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age uint `json:"age"`
|
||||
}
|
||||
err := ToStruct(jsonData, people)
|
||||
if err == nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 非法验证:非法的float
|
||||
func TestJsonToStructErrFloat(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "test abc"
|
||||
}`
|
||||
var people struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Age float64 `json:"age"`
|
||||
}
|
||||
err := ToStruct(jsonData, people)
|
||||
if err == nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 非法验证:嵌套的数据类型错误
|
||||
func TestJsonToStructNestErrInt(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "John Doe",
|
||||
"address": {
|
||||
"number": "test abc"
|
||||
}
|
||||
}`
|
||||
type Address struct {
|
||||
Number int `json:"number"`
|
||||
}
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
Address Address `json:"address"`
|
||||
}
|
||||
people := &Person{}
|
||||
err := ToStruct(jsonData, people)
|
||||
if err == nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 合法验证:多层级嵌套
|
||||
func TestJsonToStructMoreNest(t *testing.T) {
|
||||
type Address struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Source float64 `json:"source"`
|
||||
Number int `json:"number"`
|
||||
Status bool `json:"status"`
|
||||
Address Address `json:"address"`
|
||||
Emails []string `json:"emails"`
|
||||
}
|
||||
|
||||
jsonData := `{
|
||||
"name": "John Doe",
|
||||
"age": 30,
|
||||
"source": "99.99",
|
||||
"status": true,
|
||||
"address": {
|
||||
"city": "Shanghai",
|
||||
"country": "China"
|
||||
},
|
||||
"emails": [
|
||||
"john.doe@example.com",
|
||||
"jdoe@example.com"
|
||||
]
|
||||
}`
|
||||
|
||||
expectedPerson := Person{
|
||||
Name: "John Doe",
|
||||
Age: 30,
|
||||
Status: true,
|
||||
Address: Address{
|
||||
City: "Shanghai",
|
||||
Country: "China",
|
||||
},
|
||||
Emails: []string{"john.doe@example.com", "jdoe@example.com"},
|
||||
}
|
||||
|
||||
var resultPerson Person
|
||||
err := ToStruct(jsonData, &resultPerson)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if resultPerson.Name != expectedPerson.Name {
|
||||
t.Errorf("Name field mismatch: expected %s but got %s", expectedPerson.Name, resultPerson.Name)
|
||||
}
|
||||
|
||||
if resultPerson.Age != expectedPerson.Age {
|
||||
t.Errorf("Age field mismatch: expected %d but got %d", expectedPerson.Age, resultPerson.Age)
|
||||
}
|
||||
|
||||
if resultPerson.Status != expectedPerson.Status {
|
||||
t.Errorf("Status field mismatch: expected %v but got %v", expectedPerson.Status, resultPerson.Status)
|
||||
}
|
||||
|
||||
if resultPerson.Address.City != expectedPerson.Address.City {
|
||||
t.Errorf("Address.City field mismatch: expected %s but got %s", expectedPerson.Address.City, resultPerson.Address.City)
|
||||
}
|
||||
|
||||
if resultPerson.Address.Country != expectedPerson.Address.Country {
|
||||
t.Errorf("Address.Country field mismatch: expected %s but got %s", expectedPerson.Address.Country, resultPerson.Address.Country)
|
||||
}
|
||||
|
||||
if len(resultPerson.Emails) != len(expectedPerson.Emails) {
|
||||
t.Errorf("Emails length mismatch: expected %d but got %d", len(expectedPerson.Emails), len(resultPerson.Emails))
|
||||
}
|
||||
|
||||
for i, expectedEmail := range expectedPerson.Emails {
|
||||
if resultPerson.Emails[i] != expectedEmail {
|
||||
t.Errorf("Emails[%d] mismatch: expected %s but got %s", i, expectedEmail, resultPerson.Emails[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合法验证:多层级嵌套
|
||||
func TestJsonToStructMoreNest2(t *testing.T) {
|
||||
var jsonData = `
|
||||
{
|
||||
"uid": 666,
|
||||
"use_id": ["hello", 5, 9],
|
||||
"age": "20",
|
||||
"equip": {
|
||||
"keyMike": true,
|
||||
"keyTom": false
|
||||
},
|
||||
"happy": {
|
||||
"k1": [1, 2, 3],
|
||||
"k2": [4, 5, 6]
|
||||
},
|
||||
"slices": [{
|
||||
"nickname": "ABC",
|
||||
"money": "20"
|
||||
}, {
|
||||
"nickname": "EFG",
|
||||
"money": "22"
|
||||
}],
|
||||
"maps": {
|
||||
"m1": {
|
||||
"name": "alis",
|
||||
"age": "20"
|
||||
},
|
||||
"m2": {
|
||||
"name": "jom",
|
||||
"age": "22"
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
type SliceVal struct {
|
||||
Nickname string `json:"nickname"`
|
||||
Money int `json:"money"`
|
||||
}
|
||||
|
||||
type MapVal struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
type Target struct {
|
||||
Uid int `json:"uid"`
|
||||
UseId []string `json:"use_id"`
|
||||
Age int `json:"age"`
|
||||
Equip map[string]bool `json:"equip"`
|
||||
Happy map[string][]int `json:"happy"`
|
||||
Slices []SliceVal `json:"slices"`
|
||||
Maps map[string]MapVal `json:"maps"`
|
||||
}
|
||||
|
||||
var res Target
|
||||
err := ToStruct(jsonData, &res)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
// jsonRes, _ := json.Marshal(res)
|
||||
// fmt.Printf("%+v \n", res)
|
||||
// fmt.Println(string(jsonRes))
|
||||
|
||||
expected := Target{
|
||||
Uid: 666,
|
||||
UseId: []string{"hello", "5", "9"},
|
||||
Age: 20,
|
||||
Equip: map[string]bool{
|
||||
"keyMike": true,
|
||||
"keyTom": false,
|
||||
},
|
||||
Happy: map[string][]int{
|
||||
"k1": {1, 2, 3},
|
||||
"k2": {4, 5, 6},
|
||||
},
|
||||
Slices: []SliceVal{
|
||||
{
|
||||
Nickname: "ABC",
|
||||
Money: 20,
|
||||
},
|
||||
{
|
||||
Nickname: "EFG",
|
||||
Money: 22,
|
||||
},
|
||||
},
|
||||
Maps: map[string]MapVal{
|
||||
"m1": {
|
||||
Name: "alis",
|
||||
Age: 20,
|
||||
},
|
||||
"m2": {
|
||||
Name: "jom",
|
||||
Age: 22,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(res, expected) {
|
||||
t.Errorf("Result not as expected.\nExpected: %+v\nActual: %+v\n", expected, res)
|
||||
}
|
||||
}
|
||||
|
||||
// 普通数据类型定义 interface
|
||||
func TestJsonToStructAny1(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "10"
|
||||
}`
|
||||
type Target struct {
|
||||
Name interface{} `json:"name"`
|
||||
Age uint `json:"age"`
|
||||
}
|
||||
var target Target
|
||||
err := ToStruct(jsonData, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 普通数据类型定义 any
|
||||
func TestJsonToStructAny2(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": "make",
|
||||
"age": "10"
|
||||
}`
|
||||
type Target struct {
|
||||
Name any `json:"name"`
|
||||
Age uint `json:"age"`
|
||||
}
|
||||
var target Target
|
||||
err := ToStruct(jsonData, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// slice 中包含 interface
|
||||
func TestJsonToStructAny3(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": ["make",6,"tom"]
|
||||
}`
|
||||
type Target struct {
|
||||
Name []interface{} `json:"name"`
|
||||
}
|
||||
var target Target
|
||||
err := ToStruct(jsonData, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// slice 中包含 any
|
||||
func TestJsonToStructAny4(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": ["make",6,"tom"]
|
||||
}`
|
||||
type Target struct {
|
||||
Name []any `json:"name"`
|
||||
}
|
||||
var target Target
|
||||
err := ToStruct(jsonData, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(target, err)
|
||||
}
|
||||
|
||||
// map 中包含 interface
|
||||
func TestJsonToStructAny5(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": {
|
||||
"key1": "mike",
|
||||
"key2": 666
|
||||
}
|
||||
}`
|
||||
type Target struct {
|
||||
Name map[string]interface{} `json:"name"`
|
||||
}
|
||||
var target Target
|
||||
err := ToStruct(jsonData, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// map 中包含 any
|
||||
func TestJsonToStructAny6(t *testing.T) {
|
||||
jsonData := `{
|
||||
"name": {
|
||||
"key1": "mike",
|
||||
"key2": 666
|
||||
}
|
||||
}`
|
||||
type Target struct {
|
||||
Name map[string]any `json:"name"`
|
||||
}
|
||||
var target Target
|
||||
err := ToStruct(jsonData, &target)
|
||||
if err != nil {
|
||||
t.Errorf("err %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 多层级json测试
|
||||
// func TestJsonToStruct4(t *testing.T) {
|
||||
// type Address struct {
|
||||
// City string `json:"city"`
|
||||
// Street string `json:"street"`
|
||||
// Zipcode uint64 `json:"zipcode"`
|
||||
// }
|
||||
//
|
||||
// type Score struct {
|
||||
// Subject string `json:"subject"`
|
||||
// Score int `json:"score"`
|
||||
// }
|
||||
//
|
||||
// type Student struct {
|
||||
// Name string `json:"name,omitempty"`
|
||||
// Age int `json:"age,omitempty"`
|
||||
// Address Address `json:"address"`
|
||||
// Scores []Score `json:"scores,omitempty"`
|
||||
// }
|
||||
// jsonStr4 := `{
|
||||
// "name": "Alice",
|
||||
// "age": 30,
|
||||
// "address": {
|
||||
// "city": "Beijing",
|
||||
// "street": "Zhangsan Street",
|
||||
// "zipcode": 100
|
||||
// },
|
||||
// "scores": [
|
||||
// {"subject": "Math", "score": 80},
|
||||
// {"subject": "English", "score": 90}
|
||||
// ]
|
||||
// }`
|
||||
//
|
||||
// var student Student
|
||||
// if err := JsonToStruct(jsonStr4, &student); err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("%+v \n", student)
|
||||
// }
|
||||
|
||||
// func TestJsonToStruct5(t *testing.T) {
|
||||
// type Student struct {
|
||||
// Name string `json:"name,omitempty"`
|
||||
// Age int `json:"age,omitempty"`
|
||||
// }
|
||||
// jsonStr4 := `{
|
||||
// "name":null,
|
||||
// "age": "30"
|
||||
// }`
|
||||
//
|
||||
// var student Student
|
||||
// if err := JsonToStruct(jsonStr4, &student); err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("%+v \n", student)
|
||||
// }
|
||||
|
||||
// func TestJsonToStruct6(t *testing.T) {
|
||||
// type Student struct {
|
||||
// Name any `json:"name,omitempty"`
|
||||
// Age int `json:"age,omitempty"`
|
||||
// }
|
||||
// jsonStr4 := `{
|
||||
// "name":"zhangsan",
|
||||
// "age": "123"
|
||||
// }`
|
||||
//
|
||||
// var student Student
|
||||
// if err := JsonToStruct(jsonStr4, &student); err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("%+v \n", student)
|
||||
// }
|
||||
|
||||
// func TestJsonToStruct7(t *testing.T) {
|
||||
// type Student struct {
|
||||
// Name bool `json:"name"`
|
||||
// Name2 uint `json:"name2"`
|
||||
// Name3 uint `json:"name3"`
|
||||
// Age int `json:"age"`
|
||||
// }
|
||||
// jsonStr4 := `{
|
||||
// "name": true,
|
||||
// "name2": -1,
|
||||
// "name3": null,
|
||||
// "age": "123"
|
||||
// }`
|
||||
//
|
||||
// var student Student
|
||||
// if err := JsonToStruct(jsonStr4, &student); err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("%#v \n", student)
|
||||
// }
|
@@ -1,60 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func toUint64Reflect(i any) (uint64, error) {
|
||||
if i == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(i)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return 0, nil
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint(), nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
intValue := v.Int()
|
||||
if intValue < 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return uint64(intValue), nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
floatValue := v.Float()
|
||||
if floatValue < 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return uint64(floatValue), nil
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
realValue := real(v.Complex())
|
||||
if realValue < 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return uint64(realValue), nil
|
||||
case reflect.String:
|
||||
if v.String() == "" {
|
||||
return 0, nil
|
||||
}
|
||||
uintValue, err := strconv.ParseUint(v.String(), 10, 64)
|
||||
if err != nil {
|
||||
return 0, ErrSyntax
|
||||
}
|
||||
return uintValue, nil
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
return 1, nil
|
||||
} else {
|
||||
return 0, nil
|
||||
}
|
||||
default:
|
||||
return 0, ErrType
|
||||
}
|
||||
}
|
@@ -1,171 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToUint64(t *testing.T) {
|
||||
var iPtr = 90
|
||||
tests := []struct {
|
||||
name string
|
||||
input any
|
||||
want uint64
|
||||
wantError error
|
||||
}{
|
||||
{
|
||||
name: "Test -float32",
|
||||
input: float32(-0.1),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test -float64",
|
||||
input: float64(-0.2),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test -int",
|
||||
input: int(-1),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test -int8",
|
||||
input: int8(-2),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test -int16",
|
||||
input: int16(-3),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test -int32",
|
||||
input: int32(-4),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test -int64",
|
||||
input: int64(-5),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test uint",
|
||||
input: uint(12),
|
||||
want: 12,
|
||||
},
|
||||
{
|
||||
name: "Test uint8",
|
||||
input: uint8(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test uint16",
|
||||
input: uint16(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test uint32",
|
||||
input: uint32(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test uint64",
|
||||
input: uint64(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test int8",
|
||||
input: int8(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test int16",
|
||||
input: int16(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test int32",
|
||||
input: int32(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test int64",
|
||||
input: int64(42),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test float32",
|
||||
input: float32(42.0),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test float64",
|
||||
input: float64(42.0),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test complex64",
|
||||
input: complex64(complex(42, 0)),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test complex128",
|
||||
input: complex128(complex(42, 0)),
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "test -complex",
|
||||
input: complex(-1, -1),
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test string",
|
||||
input: "42",
|
||||
want: 42,
|
||||
},
|
||||
{
|
||||
name: "Test invalid string",
|
||||
input: "not a number",
|
||||
wantError: ErrSyntax,
|
||||
},
|
||||
{
|
||||
name: "Test nil pointer",
|
||||
input: (*int)(nil),
|
||||
want: 0,
|
||||
wantError: nil,
|
||||
},
|
||||
{
|
||||
name: "Test bool true",
|
||||
input: true,
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "Test bool false",
|
||||
input: false,
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Test invalid type",
|
||||
input: make(chan int),
|
||||
wantError: ErrType,
|
||||
},
|
||||
{
|
||||
name: "Test point",
|
||||
input: &iPtr,
|
||||
want: 90,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
input: nil,
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := toUint64Reflect(tt.input)
|
||||
assert.Equal(t, tt.wantError, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package jsonx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrPoint 不是指针类型
|
||||
ErrPoint = errors.New("the argument to Result must be a non-nil pointer")
|
||||
// ErrNotMap 不是Map类型
|
||||
ErrNotMap = errors.New("cannot parse map, value is not a map")
|
||||
// ErrNotSlice 不是Slice类型
|
||||
ErrNotSlice = errors.New("cannot parse slice, value is not a slice")
|
||||
// ErrSyntax 指示值不具有目标类型的正确语法
|
||||
ErrSyntax = strconv.ErrSyntax
|
||||
// ErrType 指示值不具有目标类型的正确语法
|
||||
ErrType = errors.New("unsupported type")
|
||||
)
|
Reference in New Issue
Block a user