unit test jsonToStruct

This commit is contained in:
李斌
2023-03-26 13:45:55 +08:00
parent eaff5d2941
commit 8dec1889c0
14 changed files with 1618 additions and 243 deletions

View File

@@ -1,20 +1,29 @@
# jsonUtil
根据结构体的字段类型和标签来自动选择将 JSON 值转换为相应的类型。
## Introduce
支持的字段类型包括 string、int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、bool、float32 和 float64。
<details>
<summary>English</summary>
<pre>
JsonToStruct is a method that parses a JSON string into a struct. This method accepts two parameters:
- jsonData: the JSON string to be parsed
- result: a pointer to an instance of a struct used to store the parsed data
The method uses reflection to parse the struct and extracts the corresponding values from the JSON based on the fields defined in the struct and their corresponding JSON tags. If a field in the struct is a nested struct, it recursively parses the nested struct and stores the result in the parent struct.
This method can handle basic data types such as strings, integers, floating-point numbers, booleans, as well as nested structs and slices. If a value in the JSON string cannot be converted to the target type, the method will return an error.
</pre>
</details>
支持的标签有 "json"、"jsonb" 和 "mapstructure"。
- "json" 和 "jsonb" 标签指示解析 JSON 时使用的键名。
- "mapstructure" 标签指示字段名的映射关系。
<details>
<summary>简体中文</summary>
<pre>
JsonToStruct 是一个将JSON字符串解析为结构体的方法。这个方法接受两个参数:
- jsonData待解析的JSON字符串
- result用于存储解析后数据的结构体实例的指针
该方法使用了反射机制来解析结构体并根据结构体中定义的字段和对应的json标签从JSON中提取对应的值。如果结构体的字段是一个嵌套的结构体它将递归解析嵌套的结构体并将结果存储在父结构体中。
该方法可以处理基本数据类型如字符串、整数、浮点数、布尔值以及嵌套的结构体和切片。如果JSON字符串中的值无法转换为目标类型该方法将返回一个错误。
</pre>
</details>
如果 JSON 中的某些键在结构体中没有对应的字段,则它们将被忽略。
如果 JSON 中的某些键的类型与结构体中的字段类型不匹配,则会引发解析错误。
参数 jsonData 是要解析的 JSON 字符串。
参数 result 是指向要填充 JSON 值的结构体指针。
如果解析成功,则返回 nil。如果解析失败则返回解析错误。
## Install
@@ -25,6 +34,70 @@ go get -u github.com/jefferyjob/go-easy-utils/jsonUtil
## Functions
```go
// JsonToStruct 将 JSON 字符串解析为指定的结构体指针
// JsonToStruct Parses JSON into a specified structure pointer
// 将JSON解析为指定的结构体指针
func JsonToStruct(jsonData string, result interface{}) 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"
}`
type People struct {
Name string `json:"name,omitempty"`
Age int `json:"age"`
IsUse bool `json:"is_use"`
}
var people People
if err := JsonToStruct(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"`
}
jsonData2 := `{
"name": "Bob",
"age": "25",
"address": {
"city": "Shanghai",
"country": "China"
},
"interests": ["reading", "swimming"]
}`
var person Person
err := JsonToStruct(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]}
}
```

View File

@@ -2,13 +2,13 @@ package jsonUtil
import (
"encoding/json"
"github.com/jefferyjob/go-easy-utils"
"log"
"reflect"
"strconv"
"strings"
)
// JsonToStruct 将 JSON 字符串解析为指定的结构体指针
// JsonToStruct Parses JSON into a specified structure pointer
// 将JSON解析为指定的结构体指针
func JsonToStruct(jsonData string, result interface{}) error {
var data map[string]interface{}
err := json.Unmarshal([]byte(jsonData), &data)
@@ -41,27 +41,30 @@ func JsonToStruct(jsonData string, result interface{}) error {
switch fieldValue.Kind() {
case reflect.String:
fieldValue.SetString(toString(value))
fieldValue.SetString(toStringReflect(value))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val, err := toInt64(value)
val, err := toInt64Reflect(value)
if err != nil {
log.Printf("toInt64Reflect err:%s \n", err)
return err
}
fieldValue.SetInt(val)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
val, err := toUint64(value)
val, err := toUint64Reflect(value)
if err != nil {
log.Printf("toUint64Reflect err:%s \n", err)
return err
}
fieldValue.SetUint(val)
case reflect.Float32, reflect.Float64:
val, err := toFloat64(value)
val, err := toFloat64Reflect(value)
if err != nil {
log.Printf("toFloat64Reflect err:%s \n", err)
return err
}
fieldValue.SetFloat(val)
case reflect.Bool:
val := toBool(value)
val := toBoolReflect(value)
fieldValue.SetBool(val)
case reflect.Struct:
if subData, ok := value.(map[string]interface{}); ok {
@@ -98,196 +101,15 @@ func JsonToStruct(jsonData string, result interface{}) error {
// fieldValue.Set(reflect.ValueOf(value))
}
}
return nil
}
//func isJSON(jsonStr string) bool {
// var raw json.RawMessage
// return json.Unmarshal([]byte(jsonStr), &raw) == nil
//}
func convertToJSONString(data map[string]interface{}) string {
jsonBytes, _ := json.Marshal(data)
return string(jsonBytes)
}
func toBool(value interface{}) bool {
switch v := value.(type) {
case bool:
return v
case string:
return v != "" && v != "false" && v != "0"
case int, int8, int16, int32, int64:
return v != 0
case uint, uint8, uint16, uint32, uint64, uintptr:
return v != 0
case float32, float64:
return v != 0.0
case complex64, complex128:
return v != 0+0i
case nil:
return false
default:
return false
}
}
func toString(value interface{}) string {
if value == nil {
return ""
}
switch v := value.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case int8:
return strconv.FormatInt(int64(v), 10)
case int16:
return strconv.FormatInt(int64(v), 10)
case int32:
return strconv.FormatInt(int64(v), 10)
case int64:
return strconv.FormatInt(v, 10)
case uint:
return strconv.FormatUint(uint64(v), 10)
case uint8:
return strconv.FormatUint(uint64(v), 10)
case uint16:
return strconv.FormatUint(uint64(v), 10)
case uint32:
return strconv.FormatUint(uint64(v), 10)
case uint64:
return strconv.FormatUint(v, 10)
case float32:
return strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case bool:
return strconv.FormatBool(v)
default:
return ""
}
}
func toInt64(value interface{}) (int64, error) {
if value == nil {
return 0, nil
}
switch value.(type) {
case float32:
return int64(value.(float32)), nil
case float64:
return int64(value.(float64)), nil
case string:
intValue, err := strconv.ParseInt(value.(string), 10, 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return intValue, nil
case int:
return int64(value.(int)), nil
case int8:
return int64(value.(int8)), nil
case int16:
return int64(value.(int16)), nil
case int32:
return int64(value.(int32)), nil
case int64:
return value.(int64), nil
case interface{}:
return 0, nil
default:
return 0, go_easy_utils.ErrType
}
}
func toUint64(value interface{}) (uint64, error) {
if value == nil {
return 0, nil
}
switch value.(type) {
case float32:
v := value.(float32)
if v < 0 {
return 0, nil
}
return uint64(v), nil
case float64:
v := value.(float64)
if v < 0 {
return 0, nil
}
return uint64(v), nil
case string:
intValue, err := strconv.ParseUint(value.(string), 10, 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return intValue, nil
case uint:
return uint64(value.(uint)), nil
case uint8:
return uint64(value.(uint8)), nil
case uint16:
return uint64(value.(uint16)), nil
case uint32:
return uint64(value.(uint32)), nil
case uint64:
return value.(uint64), nil
case int:
v := value.(int)
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int8:
v := value.(int8)
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int16:
v := value.(int16)
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int32:
v := value.(int32)
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int64:
v := value.(int64)
if v < 0 {
return 0, nil
}
return uint64(v), nil
case interface{}:
return 0, nil
default:
return 0, go_easy_utils.ErrType
}
}
func toFloat64(value interface{}) (float64, error) {
if value == nil {
return 0, nil
}
switch value.(type) {
case float32:
return float64(value.(float32)), nil
case float64:
return value.(float64), nil
case string:
floatValue, err := strconv.ParseFloat(value.(string), 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return floatValue, nil
default:
return 0, go_easy_utils.ErrType
}
}

View File

@@ -6,6 +6,77 @@ import (
"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"
}`
type People struct {
Name string `json:"name,omitempty"`
Age int `json:"age"`
IsUse bool `json:"is_use"`
}
var people People
if err := JsonToStruct(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 := JsonToStruct(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]}
}
// 非法的json字符串
func TestJsonToStructErrJson(t *testing.T) {
jsonData := `{"name":}`
type People struct {
Name string `json:"name"`
}
var people People
err := JsonToStruct(jsonData, &people)
if err == nil {
t.Errorf("err %s", err)
return
}
}
func TestJsonToStruct1(t *testing.T) {
type Address struct {
City string `json:"city"`
@@ -108,38 +179,6 @@ func TestJsonToStruct2(t *testing.T) {
}
func TestJsonToStruct3(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 person2 Person
err := JsonToStruct(jsonData2, &person2)
if err != nil {
log.Fatal(err)
}
fmt.Printf("person2%+v address%+v \n", person2, person2.Address)
}
// 多层级json测试
func TestJsonToStruct4(t *testing.T) {
type Address struct {
@@ -242,7 +281,3 @@ func TestJsonToStruct7(t *testing.T) {
fmt.Printf("%#v \n", student)
}
func TestToUint64(t *testing.T) {
fmt.Println(toUint64(""))
}

42
jsonUtil/log.md Normal file
View File

@@ -0,0 +1,42 @@
// 检查解引用后的值是否为 nil
```go
if reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil() {
return 0, nil
}
```
```go
v := reflect.ValueOf(i)
for v.Kind() == reflect.Ptr {
if v.IsNil() {
return 0, nil
}
v = v.Elem()
}
```
这两个写法都是使用反射判断指针是否为nil但它们的实现方式略有不同。
第一种写法将值i转换为反射值并检查其种类是否为指针reflect.Ptr然后检查其是否为nilreflect.Value.IsNil()。如果是则返回0和nil。
第二种写法首先获取值i的反射值v并检查其种类是否为指针。如果是则继续获取其指向的元素reflect.Value.Elem()并将其赋给v以便进一步检查。这个过程一直重复直到v不再是指针或者v指向的元素不是nil为止。
两种写法都可以检查指针是否为nil但第二种写法允许进一步检查指针指向的元素是否为nil因此更加灵活和精确。
```go
```
// 如果是指针类型
//这段代码的作用是将value指向的值转换为非指针类型的值具体来说它会循环检查v是否为指针类型如果是指针类型则通过Elem方法获取其指向的值直到v不再是指针类型为止。
//
//在reflect包中指针类型和其指向的值的类型是不同的。例如一个指向int类型的指针其类型是*int而其指向的值的类型是int。因此在使用reflect包时我们需要注意区分指针类型和其指向的值的类型否则可能会出现类型错误等问题。
//
//因此对于value为指针类型的情况我们需要通过Elem方法获取其指向的值然后再进行类型转换。而在使用Elem方法之前我们需要先检查v是否为指针类型因此使用循环语句进行判断。

113
jsonUtil/to_bool.go Normal file
View File

@@ -0,0 +1,113 @@
package jsonUtil
import (
"fmt"
"reflect"
)
func toBool(i interface{}) bool {
if i == nil {
return false
}
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return false
}
i = reflect.ValueOf(i).Elem().Interface()
}
switch v := i.(type) {
case bool:
return v
case int:
return v != 0
case int8:
return v != 0
case int16:
return v != 0
case int32:
return v != 0
case int64:
return v != 0
case uint:
return v != 0
case uint8:
return v != 0
case uint16:
return v != 0
case uint32:
return v != 0
case uint64:
return v != 0
case uintptr:
return v != 0
case float32:
return v != 0
case float64:
return v != 0
case complex64:
return v != 0
case complex128:
return v != 0
case string:
if v == "true" {
return true
} else if v == "false" {
return false
}
return v != ""
case fmt.Stringer:
return v.String() != ""
case interface{ IsNil() bool }:
return !v.IsNil()
default:
return false
}
}
func toBoolReflect(i interface{}) bool {
if i == nil {
return false
}
// 检查解引用后的值是否为 nil
if reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil() {
return false
}
v := reflect.ValueOf(i)
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return false
}
v = reflect.ValueOf(i).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 v.String() != ""
//case reflect.Ptr, reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Slice:
// return !v.IsNil()
default:
return false
}
}

57
jsonUtil/to_bool_test.go Normal file
View File

@@ -0,0 +1,57 @@
package jsonUtil
import "testing"
func TestToBool(t *testing.T) {
var tests = []struct {
input interface{}
want bool
}{
{true, true},
{false, false},
{int(-1), true},
{int(1), true},
{int(0), false},
{int8(1), true},
{int8(0), false},
{int16(1), true},
{int16(0), false},
{int32(1), true},
{int32(0), false},
{int64(1), true},
{int64(0), false},
{uint(1), true},
{uint(0), false},
{uint8(1), true},
{uint8(0), false},
{uint16(1), true},
{uint16(0), false},
{uint32(1), true},
{uint32(0), false},
{uint64(1), true},
{uint64(0), false},
{float32(1.0), true},
{float32(0.0), false},
{float64(1.0), true},
{float64(0.0), false},
{"abc", true},
{"true", true},
{"false", false},
{"", false},
{nil, false},
{complex64(1 + 1i), true},
{complex64(0 + 0i), false},
{complex128(1 + 1i), true},
{complex128(0 + 0i), false},
{(*int)(nil), false},
}
for _, test := range tests {
if got := toBool(test.input); got != test.want {
t.Errorf("toBool(%v) = %v; want %v", test.input, got, test.want)
}
if got := toBoolReflect(test.input); got != test.want {
t.Errorf("toBool(%v) = %v; want %v", test.input, got, test.want)
}
}
}

156
jsonUtil/to_float.go Normal file
View File

@@ -0,0 +1,156 @@
package jsonUtil
import (
"fmt"
"github.com/jefferyjob/go-easy-utils"
"reflect"
"strconv"
)
func toFloat64(i interface{}) (float64, error) {
if i == nil {
return 0, nil
}
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return 0, nil
}
i = reflect.ValueOf(i).Elem().Interface()
}
switch v := i.(type) {
case float32:
return float64(v), nil
case float64:
return v, nil
case string:
floatValue, err := strconv.ParseFloat(v, 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return floatValue, nil
case uint:
return float64(v), nil
case uint8:
return float64(v), nil
case uint16:
return float64(v), nil
case uint32:
return float64(v), nil
case uint64:
return float64(v), nil
case int:
return float64(v), nil
case int8:
return float64(v), nil
case int16:
return float64(v), nil
case int32:
return float64(v), nil
case int64:
return float64(v), nil
case complex64:
return float64(real(v)), nil
case complex128:
return real(v), nil
case bool:
if v {
return 1, nil
} else {
return 0, nil
}
//case *float32:
// return float64(*v), nil
//case *float64:
// return *v, nil
//case *string:
// floatValue, err := strconv.ParseFloat(*v, 64)
// if err != nil {
// return 0, go_easy_utils.ErrSyntax
// }
// return floatValue, nil
//case *uint:
// return float64(*v), nil
//case *uint8:
// return float64(*v), nil
//case *uint16:
// return float64(*v), nil
//case *uint32:
// return float64(*v), nil
//case *uint64:
// return float64(*v), nil
//case *int:
// return float64(*v), nil
//case *int8:
// return float64(*v), nil
//case *int16:
// return float64(*v), nil
//case *int32:
// return float64(*v), nil
//case *int64:
// return float64(*v), nil
//case *complex64:
// return float64(real(*v)), nil
//case *complex128:
// return real(*v), nil
//case *bool:
// if v != nil && *v {
// return 1, nil
// } else {
// return 0, nil
// }
default:
return 0, go_easy_utils.ErrType
}
}
func toFloat64Reflect(i interface{}) (float64, error) {
if i == nil {
return 0, nil
}
// 检查解引用后的值是否为 nil
if reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil() {
return 0, nil
}
v := reflect.ValueOf(i)
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return 0, nil
}
v = reflect.ValueOf(i).Elem()
}
switch v.Kind() {
case reflect.Float32, reflect.Float64:
return v.Float(), nil
case reflect.String:
floatValue, err := strconv.ParseFloat(v.String(), 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return floatValue, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
fmt.Println("怎么可以到这里呢")
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, go_easy_utils.ErrType
}
}

279
jsonUtil/to_float_test.go Normal file
View File

@@ -0,0 +1,279 @@
package jsonUtil
import (
go_easy_utils "github.com/jefferyjob/go-easy-utils"
"reflect"
"testing"
)
//func TestFloat(t *testing.T) {
// var data1 interface{}
// data1 = 123
// fmt.Println(toFloat64Reflect(data1))
//
// data2 := int16Ptr(80)
// fmt.Println(toFloat64Reflect(data2))
//
// data3 := map[interface{}]interface{}{
// "aaa": "aaa",
// }
// fmt.Println(toFloat64Reflect(data3))
//}
func TestToFloat64(t *testing.T) {
testCases := []struct {
value interface{}
expected float64
expectedErr error
}{
{nil, 0, nil},
{float32(123.5), 123.5, nil},
{"123.456", 123.456, nil},
{uint(123), 123, nil},
{uint8(123), 123, nil},
{uint16(123), 123, nil},
{uint32(123), 123, nil},
{uint64(123), 123, nil},
{int(123), 123, nil},
{int8(123), 123, nil},
{int16(123), 123, nil},
{int32(123), 123, nil},
{int64(123), 123, nil},
{complex64(1 + 2i), 1, nil},
{complex128(1 + 2i), 1, nil},
{true, 1, nil},
{false, 0, nil},
{(*bool)(nil), 0, nil},
}
for _, tc := range testCases {
f, err := toFloat64(tc.value)
if f != tc.expected || err != tc.expectedErr {
t.Errorf("toFloat64(%v) = (%v, %v), expected (%v, %v)", tc.value, f, err, tc.expected, tc.expectedErr)
}
f2, err2 := toFloat64Reflect(tc.value)
if f != tc.expected || err2 != tc.expectedErr {
t.Errorf("toFloat64Reflect(%v) = (%v, %v), expected (%v, %v)", tc.value, f2, err2, tc.expected, tc.expectedErr)
}
}
}
func TestToFloat64Pointer(t *testing.T) {
testCases := []struct {
name string
input interface{}
expectedValue float64
expectedError error
}{
{
name: "nil input",
input: nil,
expectedValue: 0,
expectedError: nil,
},
{
name: "float32 pointer input",
input: float32Ptr(12.2),
expectedValue: 12.199999809265137,
expectedError: nil,
},
{
name: "float64 pointer input",
input: float64Ptr(56.78),
expectedValue: 56.78,
expectedError: nil,
},
{
name: "invalid string input",
input: stringPtr("abc"),
expectedValue: 0,
expectedError: go_easy_utils.ErrSyntax,
},
{
name: "valid string input",
input: stringPtr("123.45"),
expectedValue: 123.45,
expectedError: nil,
},
{
name: "uint pointer input",
input: uintPtr(10),
expectedValue: 10,
expectedError: nil,
},
{
name: "uint8 pointer input",
input: uint8Ptr(20),
expectedValue: 20,
expectedError: nil,
},
{
name: "uint16 pointer input",
input: uint16Ptr(30),
expectedValue: 30,
expectedError: nil,
},
{
name: "uint32 pointer input",
input: uint32Ptr(40),
expectedValue: 40,
expectedError: nil,
},
{
name: "uint64 pointer input",
input: uint64Ptr(50),
expectedValue: 50,
expectedError: nil,
},
{
name: "int pointer input",
input: intPtr(-60),
expectedValue: -60,
expectedError: nil,
},
{
name: "int8 pointer input",
input: int8Ptr(-70),
expectedValue: -70,
expectedError: nil,
},
{
name: "int16 pointer input",
input: int16Ptr(-80),
expectedValue: -80,
expectedError: nil,
},
{
name: "int32 pointer input",
input: int32Ptr(-90),
expectedValue: -90,
expectedError: nil,
},
{
name: "int64 pointer input",
input: int64Ptr(-100),
expectedValue: -100,
expectedError: nil,
},
{
name: "complex64 pointer input",
input: complex64Ptr(complex(1, 2)),
expectedValue: 1,
expectedError: nil,
},
{
name: "complex128 pointer input",
input: complex128Ptr(complex(3, 4)),
expectedValue: 3,
expectedError: nil,
},
{
name: "bool pointer input - true",
input: boolPtr(true),
expectedValue: 1,
expectedError: nil,
},
{
name: "bool pointer input - false",
input: boolPtr(false),
expectedValue: 0,
expectedError: nil,
},
{
name: "unsupported input type",
input: "unsupported",
expectedValue: 0,
expectedError: go_easy_utils.ErrSyntax,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actualValue, actualError := toFloat64(tc.input)
if actualError != tc.expectedError {
t.Errorf("Expected(name:%s) error: %v, but got: %v", tc.name, tc.expectedError, actualError)
}
if !reflect.DeepEqual(actualValue, tc.expectedValue) {
t.Errorf("Expected value: %v, but got: %v", tc.expectedValue, actualValue)
}
// Reflect
actualValue2, actualError2 := toFloat64Reflect(tc.input)
if actualError2 != tc.expectedError {
t.Errorf("Expected(name:%s) error: %v, but got: %v", tc.name, tc.expectedError, actualError2)
}
if !reflect.DeepEqual(actualValue2, tc.expectedValue) {
t.Errorf("Expected value: %v, but got: %v", tc.expectedValue, actualValue2)
}
})
}
}
func float32Ptr(v float32) *float32 {
return &v
}
func float64Ptr(v float64) *float64 {
return &v
}
func stringPtr(v string) *string {
return &v
}
func uintPtr(v uint) *uint {
return &v
}
func uint8Ptr(v uint8) *uint8 {
return &v
}
func uint16Ptr(v uint16) *uint16 {
return &v
}
func uint32Ptr(v uint32) *uint32 {
return &v
}
func uint64Ptr(v uint64) *uint64 {
return &v
}
func intPtr(v int) *int {
return &v
}
func int8Ptr(v int8) *int8 {
return &v
}
func int16Ptr(v int16) *int16 {
return &v
}
func int32Ptr(v int32) *int32 {
return &v
}
func int64Ptr(v int64) *int64 {
return &v
}
func complex64Ptr(v complex64) *complex64 {
return &v
}
func complex128Ptr(v complex128) *complex128 {
return &v
}
func boolPtr(v bool) *bool {
return &v
}

168
jsonUtil/to_int.go Normal file
View File

@@ -0,0 +1,168 @@
package jsonUtil
import (
"github.com/jefferyjob/go-easy-utils"
"reflect"
"strconv"
)
func toInt64(i interface{}) (int64, error) {
if i == nil {
return 0, nil
}
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return 0, nil
}
i = reflect.ValueOf(i).Elem().Interface()
}
switch v := i.(type) {
case bool:
if v {
return 1, nil
}
return 0, nil
case uint:
return int64(v), nil
case uint8:
return int64(v), nil
case uint16:
return int64(v), nil
case uint32:
return int64(v), nil
case uint64:
return int64(v), nil
case float32:
return int64(v), nil
case float64:
return int64(v), nil
case complex64:
return int64(real(v)), nil
case complex128:
return int64(real(v)), nil
case string:
intValue, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return intValue, nil
case int:
return int64(v), nil
case int8:
return int64(v), nil
case int16:
return int64(v), nil
case int32:
return int64(v), nil
case int64:
return v, nil
//case *bool:
// if v == nil {
// return 0, nil
// }
// if *v {
// return 1, nil
// }
// return 0, nil
//case *uint:
// return int64(*v), nil
//case *uint8:
// return int64(*v), nil
//case *uint16:
// return int64(*v), nil
//case *uint32:
// return int64(*v), nil
//case *uint64:
// return int64(*v), nil
//case *float32:
// return int64(*v), nil
//case *float64:
// return int64(*v), nil
//case *complex64:
// if v == nil {
// return 0, nil
// }
// return int64(real(*v)), nil
//case *complex128:
// if v == nil {
// return 0, nil
// }
// return int64(real(*v)), nil
//case *string:
// if v == nil {
// return 0, nil
// }
// intValue, err := strconv.ParseInt(*v, 10, 64)
// if err != nil {
// return 0, go_easy_utils.ErrSyntax
// }
// return intValue, nil
//case *int:
// return int64(*v), nil
//case *int8:
// return int64(*v), nil
//case *int16:
// return int64(*v), nil
//case *int32:
// return int64(*v), nil
//case *int64:
// return *v, nil
default:
return 0, go_easy_utils.ErrType
}
}
func toInt64Reflect(i interface{}) (int64, error) {
if i == nil {
return 0, nil
}
// 检查解引用后的值是否为 nil
if reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil() {
return 0, nil
}
v := reflect.ValueOf(i)
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return 0, nil
}
v = reflect.ValueOf(i).Elem()
}
switch v.Kind() {
case reflect.Float32, reflect.Float64:
return int64(v.Float()), nil
case reflect.String:
intValue, err := strconv.ParseInt(v.String(), 10, 64)
if err != nil {
return 0, go_easy_utils.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
}
//case reflect.Ptr:
// if v.IsNil() {
// return 0, nil
// }
// return toInt64Reflect(v.Elem().Interface())
default:
return 0, go_easy_utils.ErrType
}
}

54
jsonUtil/to_int_test.go Normal file
View File

@@ -0,0 +1,54 @@
package jsonUtil
import (
"github.com/jefferyjob/go-easy-utils"
"testing"
)
func TestToInt64(t *testing.T) {
var tests = []struct {
input interface{}
expected int64
err error
}{
{"123", 123, nil},
{"-234", -234, nil},
{345, 345, nil},
{-456, -456, nil},
{int8(12), 12, nil},
{int16(1238), 1238, nil},
{int32(1239), 1239, nil},
{int64(1230), 1230, nil},
{uint(1231), 1231, nil},
{uint8(123), 123, nil},
{uint16(1232), 1232, nil},
{uint32(1233), 1233, nil},
{uint64(1234), 1234, nil},
{float32(12.45), 12, nil},
{float64(123.45), 123, nil},
{true, 1, nil},
{false, 0, nil},
{complex64(1 + 2i), 1, nil},
{complex128(1 + 2i), 1, nil},
{nil, 0, nil},
{"not a number", 0, go_easy_utils.ErrSyntax},
}
for _, tt := range tests {
actual, err := toInt64(tt.input)
if err != tt.err {
t.Errorf("toInt64(%v): expected error %v, actual error %v", tt.input, tt.err, err)
}
if actual != tt.expected {
t.Errorf("toInt64(%v): expected %v, actual %v", tt.input, tt.expected, actual)
}
actual, err = toInt64Reflect(tt.input)
if err != tt.err {
t.Errorf("toInt64(%v): expected error %v, actual error %v", tt.input, tt.err, err)
}
if actual != tt.expected {
t.Errorf("toInt64(%v): expected %v, actual %v", tt.input, tt.expected, actual)
}
}
}

184
jsonUtil/to_string.go Normal file
View File

@@ -0,0 +1,184 @@
package jsonUtil
import (
"fmt"
"reflect"
"strconv"
)
func toString(i interface{}) string {
if i == nil {
return ""
}
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return ""
}
i = reflect.ValueOf(i).Elem().Interface()
}
switch v := i.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case int8:
return strconv.FormatInt(int64(v), 10)
case int16:
return strconv.FormatInt(int64(v), 10)
case int32:
return strconv.FormatInt(int64(v), 10)
case int64:
return strconv.FormatInt(v, 10)
case uint:
return strconv.FormatUint(uint64(v), 10)
case uint8:
return strconv.FormatUint(uint64(v), 10)
case uint16:
return strconv.FormatUint(uint64(v), 10)
case uint32:
return strconv.FormatUint(uint64(v), 10)
case uint64:
return strconv.FormatUint(v, 10)
case float32:
return strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case complex64:
return fmt.Sprintf("(%g+%gi)", real(v), imag(v))
case complex128:
return fmt.Sprintf("(%g+%gi)", real(v), imag(v))
case bool:
return strconv.FormatBool(v)
//case *string:
// if v == nil {
// return ""
// }
// return *v
//case *int:
// if v == nil {
// return ""
// }
// return strconv.Itoa(*v)
//case *int8:
// if v == nil {
// return ""
// }
// return strconv.FormatInt(int64(*v), 10)
//case *int16:
// if v == nil {
// return ""
// }
// return strconv.FormatInt(int64(*v), 10)
//case *int32:
// if v == nil {
// return ""
// }
// return strconv.FormatInt(int64(*v), 10)
//case *int64:
// if v == nil {
// return ""
// }
// return strconv.FormatInt(*v, 10)
//case *uint:
// if v == nil {
// return ""
// }
// return strconv.FormatUint(uint64(*v), 10)
//case *uint8:
// if v == nil {
// return ""
// }
// return strconv.FormatUint(uint64(*v), 10)
//case *uint16:
// if v == nil {
// return ""
// }
// return strconv.FormatUint(uint64(*v), 10)
//case *uint32:
// if v == nil {
// return ""
// }
// return strconv.FormatUint(uint64(*v), 10)
//case *uint64:
// if v == nil {
// return ""
// }
// return strconv.FormatUint(*v, 10)
//case *float32:
// if v == nil {
// return ""
// }
// return strconv.FormatFloat(float64(*v), 'f', -1, 32)
//case *float64:
// if v == nil {
// return ""
// }
// return strconv.FormatFloat(*v, 'f', -1, 64)
//case *complex64:
// if v == nil {
// return ""
// }
// return fmt.Sprintf("(%g+%gi)", real(*v), imag(*v))
//case *complex128:
// if v == nil {
// return ""
// }
// return fmt.Sprintf("(%g+%gi)", real(*v), imag(*v))
//case *bool:
// if v == nil {
// return ""
// }
// return strconv.FormatBool(*v)
default:
return ""
}
}
func toStringReflect(i interface{}) string {
if i == nil {
return ""
}
// 检查解引用后的值是否为 nil
if reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil() {
return ""
}
v := reflect.ValueOf(i)
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return ""
}
v = reflect.ValueOf(i).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())
//case reflect.Ptr:
// if v.IsNil() {
// return ""
// }
// return toStringReflect(v.Elem().Interface())
default:
return ""
}
}

View File

@@ -0,0 +1,41 @@
package jsonUtil
import "testing"
func TestToString(t *testing.T) {
tests := []struct {
name string
value interface{}
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"},
{"complex64", complex64(1 + 2i), "(1+2i)"},
{"complex128", complex128(3 + 4i), "(3+4i)"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := toString(tt.value); got != tt.want {
t.Errorf("ToString() = %v, want %v", got, tt.want)
}
if got := toStringReflect(tt.value); got != tt.want {
t.Errorf("ToString() = %v, want %v", got, tt.want)
}
})
}
}

223
jsonUtil/to_uint.go Normal file
View File

@@ -0,0 +1,223 @@
package jsonUtil
import (
"github.com/jefferyjob/go-easy-utils"
"reflect"
"strconv"
)
func toUint64(i interface{}) (uint64, error) {
if i == nil {
return 0, nil
}
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return 0, nil
}
i = reflect.ValueOf(i).Elem().Interface()
}
switch v := i.(type) {
case float32:
if v < 0 {
return 0, nil
}
return uint64(v), nil
case float64:
if v < 0 {
return 0, nil
}
return uint64(v), nil
case complex64:
if real(v) < 0 || imag(v) < 0 {
return 0, nil
}
return uint64(real(v)), nil
case complex128:
if real(v) < 0 || imag(v) < 0 {
return 0, nil
}
return uint64(real(v)), nil
case string:
intValue, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return intValue, nil
case bool:
if v {
return 1, nil
} else {
return 0, nil
}
case uint:
return uint64(v), nil
case uint8:
return uint64(v), nil
case uint16:
return uint64(v), nil
case uint32:
return uint64(v), nil
case uint64:
return v, nil
case int:
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int8:
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int16:
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int32:
if v < 0 {
return 0, nil
}
return uint64(v), nil
case int64:
if v < 0 {
return 0, nil
}
return uint64(v), nil
//case *float32:
// if *v < 0 {
// return 0, nil
// }
// return uint64(*v), nil
//case *float64:
// if *v < 0 {
// return 0, nil
// }
// return uint64(*v), nil
//case *complex64:
// if real(*v) < 0 || imag(*v) < 0 {
// return 0, nil
// }
// return uint64(real(*v)), nil
//case *complex128:
// if real(*v) < 0 || imag(*v) < 0 {
// return 0, nil
// }
// return uint64(real(*v)), nil
//case *string:
// intValue, err := strconv.ParseUint(*v, 10, 64)
// if err != nil {
// return 0, go_easy_utils.ErrSyntax
// }
// return intValue, nil
//case *bool:
// if *v {
// return 1, nil
// } else {
// return 0, nil
// }
//case *uint:
// return uint64(*v), nil
//case *uint8:
// return uint64(*v), nil
//case *uint16:
// return uint64(*v), nil
//case *uint32:
// return uint64(*v), nil
//case *uint64:
// return *v, nil
//case *int:
// if *v < 0 {
// return 0, nil
// }
// return uint64(*v), nil
//case *int8:
// if *v < 0 {
// return 0, nil
// }
// return uint64(*v), nil
//case *int16:
// if *v < 0 {
// return 0, nil
// }
// return uint64(*v), nil
//case *int32:
// if *v < 0 {
// return 0, nil
// }
// return uint64(*v), nil
//case *int64:
// if *v < 0 {
// return 0, nil
// }
// return uint64(*v), nil
default:
return 0, go_easy_utils.ErrType
}
}
func toUint64Reflect(i interface{}) (uint64, error) {
if i == nil {
return 0, nil
}
// 检查解引用后的值是否为 nil
if reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil() {
return 0, nil
}
v := reflect.ValueOf(i)
// 处理指针类型
if reflect.TypeOf(i).Kind() == reflect.Ptr {
if reflect.ValueOf(i).IsNil() {
return 0, nil
}
v = reflect.ValueOf(i).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:
strValue := v.String()
uintValue, err := strconv.ParseUint(strValue, 10, 64)
if err != nil {
return 0, go_easy_utils.ErrSyntax
}
return uintValue, nil
case reflect.Bool:
if v.Bool() {
return 1, nil
} else {
return 0, nil
}
//case reflect.Ptr, reflect.Interface:
// if v.IsNil() {
// return 0, nil
// }
// return toUint64(v.Elem().Interface())
default:
return 0, go_easy_utils.ErrType
}
}

128
jsonUtil/to_uint_test.go Normal file
View File

@@ -0,0 +1,128 @@
package jsonUtil
import (
"github.com/jefferyjob/go-easy-utils"
"testing"
)
func TestToUint64(t *testing.T) {
tests := []struct {
name string
input interface{}
want uint64
wantError error
}{
{
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 string",
input: "42",
want: 42,
},
{
name: "Test invalid string",
input: "not a number",
wantError: go_easy_utils.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: go_easy_utils.ErrType,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := toUint64(tt.input)
if err != tt.wantError {
t.Errorf("toUint64(%v) error = %v, wantError %v", tt.input, err, tt.wantError)
}
if got != tt.want {
t.Errorf("toUint64(%v) = %v, want %v", tt.input, got, tt.want)
}
// Reflect
got2, err2 := toUint64Reflect(tt.input)
if err2 != tt.wantError {
t.Errorf("toUint64Reflect(%v) error = %v, wantError %v", tt.input, err2, tt.wantError)
}
if got2 != tt.want {
t.Errorf("toUint64Reflect(%v) = %v, want %v", tt.input, got2, tt.want)
}
})
}
}