优化any转string

This commit is contained in:
Yun
2025-09-02 15:43:26 +08:00
parent ab8524e5ef
commit 15e1ed41f4
5 changed files with 297 additions and 70 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ func AutoConv(toType string, target interface{}) (interface{}, error) {
case "int32": case "int32":
v, err = ToInt32(target) v, err = ToInt32(target)
case "string": case "string":
v, err = ToString(target) v = ToString(target)
} }
return v, err return v, err
} }
+196
View File
@@ -0,0 +1,196 @@
package main
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"time"
)
// package main
// import (
// "testing"
// "time"
// )
// func TestInterfaceToString(t *testing.T) {
// tests := []struct {
// name string
// input interface{}
// want string
// }{
// {"nil", nil, ""},
// {"string", "hello", "hello"},
// {"bytes", []byte("world"), "world"},
// {"custom stringer", customStringer{}, "custom stringer implementation"},
// {"error", fmt.Errorf("test error"), "test error"},
// {"bool true", true, "true"},
// {"bool false", false, "false"},
// {"int", 42, "42"},
// {"int8", int8(8), "8"},
// {"int16", int16(16), "16"},
// {"int32", int32(32), "32"},
// {"int64", int64(64), "64"},
// {"uint", uint(42), "42"},
// {"uint8", uint8(8), "8"},
// {"uint16", uint16(16), "16"},
// {"uint32", uint32(32), "32"},
// {"uint64", uint64(64), "64"},
// {"float32", float32(3.14), "3.14"},
// {"float64", 3.1415, "3.1415"},
// {"complex64", complex64(1 + 2i), "(1+2i)"},
// {"complex128", 1 + 3i, "(1+3i)"},
// {"time", time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), "2020-01-01T00:00:00Z"},
// {"duration", time.Hour, "1h0m0s"},
// {"slice", []int{1, 2, 3}, "[1,2,3]"},
// {"array", [2]string{"a", "b"}, `["a","b"]`},
// {"map", map[string]int{"a": 1}, `{"a":1}`},
// {"struct", struct{ A int }{42}, `{"A":42}`},
// {"pointer to int", intPtr(42), "42"},
// {"pointer to nil", (*int)(nil), ""},
// {"custom type", TestStr("custom"), "custom"},
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// if got := InterfaceToString(tt.input); got != tt.want {
// t.Errorf("InterfaceToString() = %v, want %v", got, tt.want)
// }
// })
// }
// }
// func intPtr(i int) *int {
// return &i
// }
// InterfaceToString 将任意interface转换为string
func InterfaceToString(v interface{}) string {
if v == nil {
return ""
}
// 获取值的反射对象
val := reflect.ValueOf(v)
// 处理指针类型:解引用直到获取到非指针值
for val.Kind() == reflect.Ptr {
if val.IsNil() {
return ""
}
val = val.Elem()
}
// 获取解引用后的实际值
actualValue := val.Interface()
// 根据具体类型进行处理
switch actual := actualValue.(type) {
case string:
return actual
case []byte:
return string(actual)
case fmt.Stringer:
return actual.String()
case error:
return actual.Error()
case bool:
return strconv.FormatBool(actual)
case int:
return strconv.Itoa(actual)
case int8:
return strconv.FormatInt(int64(actual), 10)
case int16:
return strconv.FormatInt(int64(actual), 10)
case int32:
return strconv.FormatInt(int64(actual), 10)
case int64:
return strconv.FormatInt(actual, 10)
case uint:
return strconv.FormatUint(uint64(actual), 10)
case uint8:
return strconv.FormatUint(uint64(actual), 10)
case uint16:
return strconv.FormatUint(uint64(actual), 10)
case uint32:
return strconv.FormatUint(uint64(actual), 10)
case uint64:
return strconv.FormatUint(actual, 10)
case float32:
return strconv.FormatFloat(float64(actual), 'f', -1, 32)
case float64:
return strconv.FormatFloat(actual, 'f', -1, 64)
case complex64:
return fmt.Sprint(actual)
case complex128:
return fmt.Sprint(actual)
case time.Time:
return actual.Format(time.RFC3339)
case time.Duration:
return actual.String()
}
// 处理切片、数组、map、结构体等复杂类型 - 使用JSON序列化
if val.IsValid() {
switch val.Kind() {
case reflect.Slice, reflect.Array, reflect.Map, reflect.Struct:
jsonBytes, err := json.Marshal(actualValue)
if err == nil {
return string(jsonBytes)
}
}
}
// 默认处理:使用fmt.Sprint
return fmt.Sprint(actualValue)
}
// 示例用法
func main() {
// 测试各种类型
testCases := []interface{}{
nil,
"hello",
42,
3.14,
true,
[]byte("world"),
[]int{1, 2, 3},
map[string]interface{}{"name": "John", "age": 30},
struct {
Name string `json:"name"`
Age int `json:"age"`
}{"Alice", 25},
time.Now(),
time.Hour * 2,
// 指针类型
&[]string{"a", "b", "c"},
// 自定义Stringer
customStringer{},
// 错误类型
fmt.Errorf("test error"),
TestStrOne,
2454528425152485425,
}
for i, tc := range testCases {
result := InterfaceToString(tc)
fmt.Printf("Case %d: %T -> %s\n", i+1, tc, result)
}
}
// 自定义Stringer实现
type customStringer struct{}
func (c customStringer) String() string {
return "custom stringer implementation"
}
type TestStr string
const (
TestStrOne TestStr = "1"
)
+12 -30
View File
@@ -30,11 +30,8 @@ func TestConvToString(t *testing.T) {
// 测试int // 测试int
var v_int int = 123456789 var v_int int = 123456789
str, err := convx.ToString(v_int) str := convx.ToString(v_int)
if err != nil {
t.Fail()
t.Log(err)
}
if str != "123456789" { if str != "123456789" {
t.Fail() t.Fail()
t.Log(str) t.Log(str)
@@ -42,11 +39,8 @@ func TestConvToString(t *testing.T) {
// 测试int32 // 测试int32
var v_int32 int32 = 123456789 var v_int32 int32 = 123456789
str, err = convx.ToString(v_int32) str = convx.ToString(v_int32)
if err != nil {
t.Fail()
t.Log(err)
}
if str != "123456789" { if str != "123456789" {
t.Fail() t.Fail()
t.Log(str) t.Log(str)
@@ -54,11 +48,8 @@ func TestConvToString(t *testing.T) {
// 测试int64 // 测试int64
var v_int64 int64 = 123456789 var v_int64 int64 = 123456789
str, err = convx.ToString(v_int64) str = convx.ToString(v_int64)
if err != nil {
t.Fail()
t.Log(err)
}
if str != "123456789" { if str != "123456789" {
t.Fail() t.Fail()
t.Log(str) t.Log(str)
@@ -66,11 +57,8 @@ func TestConvToString(t *testing.T) {
// 测试float32 // 测试float32
var v_float32 float32 = 123.12345 var v_float32 float32 = 123.12345
str, err = convx.ToString(v_float32) str = convx.ToString(v_float32)
if err != nil {
t.Fail()
t.Log(err)
}
if str != "123.12345" { if str != "123.12345" {
t.Fail() t.Fail()
t.Log(str) t.Log(str)
@@ -78,11 +66,8 @@ func TestConvToString(t *testing.T) {
// 测试float64 // 测试float64
var v_float64 float64 = 123456789.12345 var v_float64 float64 = 123456789.12345
str, err = convx.ToString(v_float64) str = convx.ToString(v_float64)
if err != nil {
t.Fail()
t.Log(err)
}
if str != "123456789.12345" { if str != "123456789.12345" {
t.Fail() t.Fail()
t.Log(str) t.Log(str)
@@ -90,11 +75,8 @@ func TestConvToString(t *testing.T) {
// 测试string // 测试string
var v_string string = "123456789.12345" var v_string string = "123456789.12345"
str, err = convx.ToString(v_string) str = convx.ToString(v_string)
if err != nil {
t.Fail()
t.Log(err)
}
if str != "123456789.12345" { if str != "123456789.12345" {
t.Fail() t.Fail()
t.Log(str) t.Log(str)
+72 -27
View File
@@ -1,46 +1,91 @@
package convx package convx
import ( import (
"errors" "encoding/json"
"fmt" "fmt"
"reflect"
"strconv" "strconv"
"time"
) )
// interface 转 string // interface 转 string
func ToString(val interface{}) (str string, err error) { // InterfaceToString 将任意interface转换为string
func ToString(v interface{}) string {
if v == nil {
return ""
}
switch v := val.(type) { // 获取值的反射对象
case nil: val := reflect.ValueOf(v)
return "", fmt.Errorf("can not convert to string")
// 处理指针类型:解引用直到获取到非指针值
for val.Kind() == reflect.Ptr {
if val.IsNil() {
return ""
}
val = val.Elem()
}
// 获取解引用后的实际值
actualValue := val.Interface()
// 根据具体类型进行处理
switch actual := actualValue.(type) {
case string: case string:
return v, nil return actual
case int: case []byte:
return strconv.Itoa(v), nil return string(actual)
case int8: case error:
return strconv.FormatInt(int64(v), 10), nil return actual.Error()
case int16:
return strconv.FormatInt(int64(v), 10), nil
case int32:
return strconv.FormatInt(int64(v), 10), nil
case int64:
return strconv.FormatInt(v, 10), nil
case float32:
return strconv.FormatFloat(float64(v), 'f', -1, 32), nil
case float64:
return strconv.FormatFloat(v, 'f', -1, 64), nil
case bool: case bool:
return strconv.FormatBool(v), nil return strconv.FormatBool(actual)
case int:
return strconv.Itoa(actual)
case int8:
return strconv.FormatInt(int64(actual), 10)
case int16:
return strconv.FormatInt(int64(actual), 10)
case int32:
return strconv.FormatInt(int64(actual), 10)
case int64:
return strconv.FormatInt(actual, 10)
case uint: case uint:
return strconv.FormatUint(uint64(v), 10), nil return strconv.FormatUint(uint64(actual), 10)
case uint8: case uint8:
return strconv.FormatUint(uint64(v), 10), nil return strconv.FormatUint(uint64(actual), 10)
case uint16: case uint16:
return strconv.FormatUint(uint64(v), 10), nil return strconv.FormatUint(uint64(actual), 10)
case uint32: case uint32:
return strconv.FormatUint(uint64(v), 10), nil return strconv.FormatUint(uint64(actual), 10)
case uint64: case uint64:
return strconv.FormatUint(v, 10), nil return strconv.FormatUint(actual, 10)
case float32:
return strconv.FormatFloat(float64(actual), 'f', -1, 32)
case float64:
return strconv.FormatFloat(actual, 'f', -1, 64)
case complex64:
return fmt.Sprint(actual)
case complex128:
return fmt.Sprint(actual)
case time.Time:
return actual.Format(time.RFC3339)
case time.Duration:
return actual.String()
case fmt.Stringer:
return actual.String()
} }
return "", errors.New("can not convert to string") // 处理切片、数组、map、结构体等复杂类型 - 使用JSON序列化
if val.IsValid() {
switch val.Kind() {
case reflect.Slice, reflect.Array, reflect.Map, reflect.Struct:
jsonBytes, err := json.Marshal(actualValue)
if err == nil {
return string(jsonBytes)
}
}
}
// 默认处理:使用fmt.Sprint
return fmt.Sprint(actualValue)
} }
+8 -4
View File
@@ -6,6 +6,12 @@ import (
"code.yun.ink/pkg/convx" "code.yun.ink/pkg/convx"
) )
type TestStr string
const (
TestStrOne TestStr = "1"
)
func TestToString(t *testing.T) { func TestToString(t *testing.T) {
var tests = []struct { var tests = []struct {
@@ -26,13 +32,11 @@ func TestToString(t *testing.T) {
{uint16(1), "1"}, //uint16 {uint16(1), "1"}, //uint16
{uint32(1), "1"}, //uint32 {uint32(1), "1"}, //uint32
{uint64(1), "1"}, //uint64 {uint64(1), "1"}, //uint64
{TestStrOne, "1"}, //custom type
} }
for _, test := range tests { for _, test := range tests {
str, err := convx.ToString(test.input) str := convx.ToString(test.input)
if err != nil {
t.Errorf("convx.ToString(%v) failed with %v", test.input, err)
}
if str != test.expect { if str != test.expect {
t.Errorf("convx.ToString(%v) = %v, want %v", test.input, str, test.expect) t.Errorf("convx.ToString(%v) = %v, want %v", test.input, str, test.expect)
} }