Files
gf/g/util/gconv/gconv.go

367 lines
9.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// 类型转换.
// 内部使用了bytes作为底层转换类型效率很高。
package gconv
import (
"fmt"
"time"
"strconv"
"encoding/json"
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/util/gstr"
"gitee.com/johng/gf/g/encoding/gbinary"
"github.com/fatih/structs"
"strings"
"reflect"
)
// 将变量i转换为字符串指定的类型t
func Convert(i interface{}, t string, params...interface{}) interface{} {
switch t {
case "int": return Int(i)
case "int8": return Int8(i)
case "int16": return Int16(i)
case "int32": return Int32(i)
case "int64": return Int64(i)
case "uint": return Uint(i)
case "uint8": return Uint8(i)
case "uint16": return Uint16(i)
case "uint32": return Uint32(i)
case "uint64": return Uint64(i)
case "float32": return Float32(i)
case "float64": return Float64(i)
case "bool": return Bool(i)
case "string": return String(i)
case "[]byte": return Bytes(i)
case "time.Time":
if len(params) > 0 {
return Time(i, String(params[0]))
}
return Time(i)
case "time.Duration": return TimeDuration(i)
default:
return i
}
}
// 将变量i转换为time.Time类型
func Time(i interface{}, format...string) time.Time {
s := String(i)
// 优先使用用户输入日期格式进行转换
if len(format) > 0 {
t, _ := gtime.StrToTimeFormat(s, format[0])
return t
}
if gstr.IsNumeric(s) {
return gtime.NewFromTimeStamp(Int64(s)).Time
} else {
t, _ := gtime.StrToTime(s)
return t
}
}
// 将变量i转换为time.Time类型
func TimeDuration(i interface{}) time.Duration {
return time.Duration(Int64(i))
}
func Bytes(i interface{}) []byte {
if i == nil {
return nil
}
if r, ok := i.([]byte); ok {
return r
} else {
return gbinary.Encode(i)
}
}
// 基础的字符串类型转换
func String(i interface{}) string {
if i == nil {
return ""
}
switch value := i.(type) {
case int: return strconv.Itoa(value)
case int8: return strconv.Itoa(int(value))
case int16: return strconv.Itoa(int(value))
case int32: return strconv.Itoa(int(value))
case int64: return strconv.Itoa(int(value))
case uint: return strconv.FormatUint(uint64(value), 10)
case uint8: return strconv.FormatUint(uint64(value), 10)
case uint16: return strconv.FormatUint(uint64(value), 10)
case uint32: return strconv.FormatUint(uint64(value), 10)
case uint64: return strconv.FormatUint(uint64(value), 10)
case float32: return strconv.FormatFloat(float64(value), 'f', -1, 32)
case float64: return strconv.FormatFloat(value, 'f', -1, 64)
case bool: return strconv.FormatBool(value)
case string: return value
case []byte: return string(value)
default:
// 默认使用json进行字符串转换
jsonContent, _ := json.Marshal(value)
return string(jsonContent)
}
}
func Strings(i interface{}) []string {
if i == nil {
return nil
}
if r, ok := i.([]string); ok {
return r
} else if r, ok := i.([]interface{}); ok {
strs := make([]string, len(r))
for k, v := range r {
strs[k] = String(v)
}
return strs
}
return []string{fmt.Sprintf("%v", i)}
}
//false: "", 0, false, off
func Bool(i interface{}) bool {
if i == nil {
return false
}
if v, ok := i.(bool); ok {
return v
}
if s := String(i); s != "" && s != "0" && s != "false" && s != "off" {
return true
}
return false
}
func Int(i interface{}) int {
if i == nil {
return 0
}
switch value := i.(type) {
case int: return value
case int8: return int(value)
case int16: return int(value)
case int32: return int(value)
case int64: return int(value)
case uint: return int(value)
case uint8: return int(value)
case uint16: return int(value)
case uint32: return int(value)
case uint64: return int(value)
case float32: return int(value)
case float64: return int(value)
case bool:
if value {
return 1
}
return 0
default:
v, _ := strconv.Atoi(String(value))
return v
}
}
func Int8(i interface{}) int8 {
if i == nil {
return 0
}
if v, ok := i.(int8); ok {
return v
}
return int8(Int(i))
}
func Int16(i interface{}) int16 {
if i == nil {
return 0
}
if v, ok := i.(int16); ok {
return v
}
return int16(Int(i))
}
func Int32(i interface{}) int32 {
if i == nil {
return 0
}
if v, ok := i.(int32); ok {
return v
}
return int32(Int(i))
}
func Int64(i interface{}) int64 {
if i == nil {
return 0
}
if v, ok := i.(int64); ok {
return v
}
return int64(Int(i))
}
func Uint(i interface{}) uint {
if i == nil {
return 0
}
switch value := i.(type) {
case int: return uint(value)
case int8: return uint(value)
case int16: return uint(value)
case int32: return uint(value)
case int64: return uint(value)
case uint: return value
case uint8: return uint(value)
case uint16: return uint(value)
case uint32: return uint(value)
case uint64: return uint(value)
case float32: return uint(value)
case float64: return uint(value)
case bool:
if value {
return 1
}
return 0
default:
v, _ := strconv.ParseUint(String(value), 10, 64)
return uint(v)
}
}
func Uint8(i interface{}) uint8 {
if i == nil {
return 0
}
if v, ok := i.(uint8); ok {
return v
}
return uint8(Uint(i))
}
func Uint16(i interface{}) uint16 {
if i == nil {
return 0
}
if v, ok := i.(uint16); ok {
return v
}
return uint16(Uint(i))
}
func Uint32(i interface{}) uint32 {
if i == nil {
return 0
}
if v, ok := i.(uint32); ok {
return v
}
return uint32(Uint(i))
}
func Uint64(i interface{}) uint64 {
if i == nil {
return 0
}
if v, ok := i.(uint64); ok {
return v
}
return uint64(Uint(i))
}
func Float32 (i interface{}) float32 {
if i == nil {
return 0
}
if v, ok := i.(float32); ok {
return v
}
v, _ := strconv.ParseFloat(String(i), 64)
return float32(v)
}
func Float64 (i interface{}) float64 {
if i == nil {
return 0
}
if v, ok := i.(float64); ok {
return v
}
v, _ := strconv.ParseFloat(String(i), 64)
return v
}
// 将params键值对参数映射到对应的struct对象属性上第三个参数mapping为非必需表示自定义名称与属性名称的映射关系。
// 需要注意:
// 1、第二个参数为struct对象指针
// 2、struct对象的**公开属性(首字母大写)**才能被映射赋值;
// 3、map中的键名可以为小写映射转换时会自动将键名首字母转为大写做匹配映射如果无法匹配则忽略
func MapToStruct(params map[string]interface{}, object interface{}, mapping...map[string]string) error {
tagmap := make(map[string]string)
fields := structs.Fields(object)
// 将struct中定义的属性转换名称构建称tagmap
for _, field := range fields {
if tag := field.Tag("gconv"); tag != "" {
for _, v := range strings.Split(tag, ",") {
tagmap[strings.TrimSpace(v)] = field.Name()
}
}
}
elem := reflect.ValueOf(object).Elem()
dmap := make(map[string]bool)
// 首先按照传递的映射关系进行匹配
if len(mapping) > 0 && len(mapping[0]) > 0 {
for mappingk, mappingv := range mapping[0] {
if v, ok := params[mappingk]; ok {
dmap[mappingv] = true
bindVarToStruct(elem, mappingv, v)
}
}
}
// 其次匹配对象定义时绑定的属性名称
for tagk, tagv := range tagmap {
if _, ok := dmap[tagv]; ok {
continue
}
if v, ok := params[tagk]; ok {
dmap[tagv] = true
bindVarToStruct(elem, tagv, v)
}
}
// 最后按照默认规则进行匹配
for mapk, mapv := range params {
name := gstr.UcFirst(mapk)
if _, ok := dmap[name]; ok {
continue
}
// 后续tag逻辑中会处理的key(重复的键名)这里便不处理
if _, ok := tagmap[mapk]; !ok {
bindVarToStruct(elem, name, mapv)
}
}
return nil
}
// 将参数值绑定到对象指定名称的属性上
func bindVarToStruct(elem reflect.Value, name string, value interface{}) {
structFieldValue := elem.FieldByName(name)
// 键名与对象属性匹配检测
if !structFieldValue.IsValid() {
return
}
// CanSet的属性必须为公开属性(首字母大写)
if !structFieldValue.CanSet() {
return
}
// 必须将value转换为struct属性的数据类型这里必须用到gconv包
structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String())))
}