1 Star 0 Fork 0

nrgo / conv

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
conv.go 10.79 KB
一键复制 编辑 原始数据 按行查看 历史
tm 提交于 2021-02-19 20:55 . #I388ZY
// Package conv 提供基本的类型转换方法
package conv
import (
"database/sql/driver"
"errors"
"fmt"
"reflect"
"strconv"
"time"
)
var (
ErrNilPtr = errors.New("destination pointer is nil")
ErrUnsupported = func(v interface{}) error { return fmt.Errorf("unsupported type: %v", v) }
)
// AsBytes 将反射值转换为原始字节流
// @buf 写入的目标缓冲流
// @rv 需要写入的反射值
// returns
// @b 写入完成的目标缓冲流
// @ok 是否写入成功
func AsBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.AppendInt(buf, rv.Int(), 10), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.AppendUint(buf, rv.Uint(), 10), true
case reflect.Float32:
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
case reflect.Float64:
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
case reflect.Bool:
return strconv.AppendBool(buf, rv.Bool()), true
case reflect.String:
s := rv.String()
return append(b, s...), true
}
return b, false
}
// AsString 将 interface 转换为 string
// @src 需要转换的源
// returns
// @string 转换后的 string
func AsString(src interface{}) string {
if src == nil {
return ``
}
switch v := src.(type) {
case string:
return v
case []byte:
return string(v)
}
rv := reflect.ValueOf(src)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(rv.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(rv.Uint(), 10)
case reflect.Float64:
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
case reflect.Float32:
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
case reflect.Bool:
return strconv.FormatBool(rv.Bool())
}
return fmt.Sprintf("%v", src)
}
// AsFloat64 将 interface 转换为 float64
// @src 需要转换的源
// returns
// @float64 转换后的 float64 值
// @error 是否转换成功
func AsFloat64(src interface{}) (float64, error) {
switch v := src.(type) {
case float32:
return float64(v), nil
case float64:
return v, nil
case string:
i, err := strconv.ParseFloat(v, 64)
if err != nil {
return 0, err
}
return i, nil
case []byte:
i, err := strconv.ParseFloat(string(v), 64)
if err != nil {
return 0, err
}
return i, nil
}
return 0, ErrUnsupported(reflect.TypeOf(src))
}
// AsFloat 将 interface 转换为 float32
// @src 需要转换的源
// returns
// @float32 转换后的 float32 值
// @error 是否转换成功
func AsFloat(src interface{}) (float32, error) {
switch v := src.(type) {
case float32:
return v, nil
case float64:
f64s := strconv.FormatFloat(v, 'g', -1, 64)
f64, err := strconv.ParseFloat(f64s, 32)
if err != nil {
return 0, err
}
return float32(f64), nil
case string:
f64, err := strconv.ParseFloat(v, 32)
if err != nil {
return 0, err
}
return float32(f64), nil
case []byte:
f64, err := strconv.ParseFloat(string(v), 32)
if err != nil {
return 0, err
}
return float32(f64), nil
}
return 0, ErrUnsupported(reflect.TypeOf(src))
}
// AsInt64 将 interface 转换为 int64
// @src 需要转换的源
// returns
// @int64 转换后的 int64 值
// @error 是否转换成功
func AsInt64(src interface{}) (int64, error) {
switch v := src.(type) {
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 []byte:
i, err := strconv.ParseInt(string(v), 10, 64)
if err != nil {
return 0, err
}
return i, nil
case string:
i, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return 0, err
}
return i, nil
}
return 0, ErrUnsupported(reflect.TypeOf(src))
}
// AsInt 将 interface 转换为 int
// @src 需要转换的源
// returns
// @int 转换后的 int32 值
// @error 是否转换成功
func AsInt(src interface{}) (int, error) {
switch v := src.(type) {
case int:
return v, nil
case int8:
return int(v), nil
case int16:
return int(v), nil
case int32:
return int(v), nil
case int64:
i64s := strconv.FormatInt(v, 10)
i64, err := strconv.ParseInt(i64s, 10, 32)
if err != nil {
return 0, err
}
return int(i64), nil
case []byte:
i64, err := strconv.ParseInt(string(v), 10, 32)
if err != nil {
return 0, err
}
return int(i64), nil
case string:
i64, err := strconv.ParseInt(v, 10, 32)
if err != nil {
return 0, err
}
return int(i64), nil
}
return 0, ErrUnsupported(reflect.TypeOf(src))
}
// AsBool 将字节流转换为 bool
// @src 需要转换的源
// returns
// @bool 转换后的 bool 值
// @error 是否转换成功
func AsBool(bs []byte) (bool, error) {
if len(bs) == 0 {
return false, nil
}
if bs[0] == 0x00 {
return false, nil
} else if bs[0] == 0x01 {
return true, nil
}
return strconv.ParseBool(string(bs))
}
// AsMapStringInterface 将 interface 转换为 map[string]interface{}
// @src 需要转换的源
// returns
// @map 转换后的 map[string]interface{}
// @error 是否转换成功
func AsMapStringInterface(src interface{}) (map[string]interface{}, error) {
t := reflect.TypeOf(src)
if t.Kind() == reflect.Map {
return src.(map[string]interface{}), nil
}
return nil, ErrUnsupported(t)
}
// AsMapInterface 将 interface 转换为 map[interface{}]interface{}
// @src 需要转换的源
// returns
// @map 转换后的 map[interface{}]interface{}
// @error 是否转换成功
func AsMapInterface(src interface{}) (map[interface{}]interface{}, error) {
t := reflect.TypeOf(src)
if t.Kind() == reflect.Map {
return src.(map[interface{}]interface{}), nil
}
return nil, ErrUnsupported(t)
}
// MapInterfaceToMapStringInterface 将 map[interface{}]interface{} 转换为 map[string]interface{}
// @src 需要转换的源
// @dest 转换的目标
func MapInterfaceToMapStringInterface(src map[interface{}]interface{}, dest map[string]interface{}) {
for ki, vi := range src {
k := ki.(string)
if collection, err := AsMapInterface(vi); err == nil {
sub := make(map[string]interface{})
MapInterfaceToMapStringInterface(collection, sub)
dest[k] = sub
} else {
dest[k] = vi
}
}
}
// ConvertAssign 将 src 中的值转换并拷贝到 dest 中
// 当转换出现丢失时,返回一个 error
// dest 为一个 pointer 类型
// @src 需要转换的源
// @dest 转换的目标
// returns
// @error 是否转换成功
func ConvertAssign(dest, src interface{}) error {
// Common cases, without reflect.
tm, err := convertAssignToCommonType(dest, src)
if tm {
return err
}
tm, err = convertAssignToComplexType(dest, src)
if tm {
return err
}
return fmt.Errorf("unsupported, storing Value type %T into type %T", src, dest)
}
func convertAssignToComplexType(dest, src interface{}) (bool, error) {
var sv reflect.Value
switch d := dest.(type) {
case *string:
sv = reflect.ValueOf(src)
switch sv.Kind() {
case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
*d = AsString(src)
return true, nil
}
case *[]byte:
sv = reflect.ValueOf(src)
if b, ok := AsBytes(nil, sv); ok {
*d = b
return true, nil
}
case *bool:
bv, err := driver.Bool.ConvertValue(src)
if err == nil {
*d = bv.(bool)
}
return true, err
case *interface{}:
*d = src
return true, nil
}
dpv := reflect.ValueOf(dest)
if dpv.Kind() != reflect.Ptr {
return true, ErrNilPtr
}
if dpv.IsNil() {
return true, ErrNilPtr
}
if !sv.IsValid() {
sv = reflect.ValueOf(src)
}
dv := reflect.Indirect(dpv)
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
switch b := src.(type) {
case []byte:
dv.Set(reflect.ValueOf(cloneBytes(b)))
default:
dv.Set(sv)
}
return true, nil
}
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
dv.Set(sv.Convert(dv.Type()))
return true, nil
}
switch dv.Kind() {
case reflect.Ptr:
if src == nil {
dv.Set(reflect.Zero(dv.Type()))
return true, nil
}
dv.Set(reflect.New(dv.Type().Elem()))
return true, ConvertAssign(dv.Interface(), src)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
s := AsString(src)
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
if err != nil {
err = strconvErr(err)
return true, fmt.Errorf("converting Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
}
dv.SetInt(i64)
return true, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
s := AsString(src)
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
if err != nil {
err = strconvErr(err)
return true, fmt.Errorf("converting Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
}
dv.SetUint(u64)
return true, nil
case reflect.Float32, reflect.Float64:
s := AsString(src)
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
if err != nil {
err = strconvErr(err)
return true, fmt.Errorf("converting Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
}
dv.SetFloat(f64)
return true, nil
case reflect.String:
dv.SetString(AsString(src))
return true, nil
}
return false, nil
}
func convertAssignToCommonType(dest, src interface{}) (bool, error) {
// Common cases, without reflect.
switch s := src.(type) {
case string:
switch d := dest.(type) {
case *string:
if d == nil {
return true, ErrNilPtr
}
*d = s
return true, nil
case *[]byte:
if d == nil {
return true, ErrNilPtr
}
*d = []byte(s)
return true, nil
}
case []byte:
switch d := dest.(type) {
case *string:
if d == nil {
return true, ErrNilPtr
}
*d = string(s)
return true, nil
case *interface{}:
if d == nil {
return true, ErrNilPtr
}
*d = cloneBytes(s)
return true, nil
case *[]byte:
if d == nil {
return true, ErrNilPtr
}
*d = cloneBytes(s)
return true, nil
}
case time.Time:
switch d := dest.(type) {
case *string:
*d = s.Format(time.RFC3339Nano)
return true, nil
case *[]byte:
if d == nil {
return true, ErrNilPtr
}
*d = []byte(s.Format(time.RFC3339Nano))
return true, nil
}
case nil:
switch d := dest.(type) {
case *interface{}:
if d == nil {
return true, ErrNilPtr
}
*d = nil
return true, nil
case *[]byte:
if d == nil {
return true, ErrNilPtr
}
*d = nil
return true, nil
}
}
return false, nil
}
func strconvErr(err error) error {
if ne, ok := err.(*strconv.NumError); ok {
return ne.Err
}
return err
}
func cloneBytes(b []byte) []byte {
if b == nil {
return nil
}
c := make([]byte, len(b))
copy(c, b)
return c
}
Go
1
https://gitee.com/nrgo/conv.git
git@gitee.com:nrgo/conv.git
nrgo
conv
conv
v0.1.1

搜索帮助