gf/util/gconv/gconv.go

789 lines
16 KiB
Go
Raw Normal View History

2021-01-17 21:46:25 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2017-12-31 11:09:16 +08:00
//
// 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://github.com/gogf/gf.
2017-12-31 18:19:58 +08:00
// Package gconv implements powerful and convenient converting functionality for any types of variables.
2020-06-04 20:13:33 +08:00
//
// This package should keep much less dependencies with other packages.
2017-12-31 11:09:16 +08:00
package gconv
import (
2019-07-22 15:31:35 +08:00
"fmt"
"github.com/gogf/gf/internal/json"
"github.com/gogf/gf/os/gtime"
2021-05-25 09:56:23 +08:00
"math"
2019-06-19 09:06:52 +08:00
"reflect"
"strconv"
"strings"
"time"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/encoding/gbinary"
2017-12-31 11:09:16 +08:00
)
type (
// errorStack is the interface for Stack feature.
errorStack interface {
Error() string
Stack() string
}
)
var (
2019-06-19 09:06:52 +08:00
// Empty strings.
emptyStringMap = map[string]struct{}{
"": {},
"0": {},
"no": {},
"off": {},
"false": {},
2019-06-19 09:06:52 +08:00
}
2021-05-25 22:16:55 +08:00
// StructTagPriority defines the default priority tags for Map*/Struct* functions.
// Note, the "gconv", "param", "params" tags are used by old version of package.
// It is strongly recommended using short tag "c" or "p" instead in the future.
2020-07-25 10:54:48 +08:00
StructTagPriority = []string{"gconv", "param", "params", "c", "p", "json"}
)
type doConvertInput struct {
FromValue interface{} // Value that is converted from.
ToTypeName string // Target value type name in string.
ReferValue interface{} // Referred value, a value in type `ToTypeName`.
Extra []interface{} // Extra values for implementing the converting.
}
// doConvert does common used types converting.
func doConvert(input doConvertInput) interface{} {
switch input.ToTypeName {
2019-06-19 09:06:52 +08:00
case "int":
return Int(input.FromValue)
case "*int":
if _, ok := input.FromValue.(*int); ok {
return input.FromValue
}
v := Int(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "int8":
return Int8(input.FromValue)
case "*int8":
if _, ok := input.FromValue.(*int8); ok {
return input.FromValue
}
v := Int8(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "int16":
return Int16(input.FromValue)
case "*int16":
if _, ok := input.FromValue.(*int16); ok {
return input.FromValue
}
v := Int16(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "int32":
return Int32(input.FromValue)
case "*int32":
if _, ok := input.FromValue.(*int32); ok {
return input.FromValue
}
v := Int32(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "int64":
return Int64(input.FromValue)
case "*int64":
if _, ok := input.FromValue.(*int64); ok {
return input.FromValue
}
v := Int64(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "uint":
return Uint(input.FromValue)
case "*uint":
if _, ok := input.FromValue.(*uint); ok {
return input.FromValue
}
v := Uint(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "uint8":
return Uint8(input.FromValue)
case "*uint8":
if _, ok := input.FromValue.(*uint8); ok {
return input.FromValue
}
v := Uint8(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "uint16":
return Uint16(input.FromValue)
case "*uint16":
if _, ok := input.FromValue.(*uint16); ok {
return input.FromValue
}
v := Uint16(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "uint32":
return Uint32(input.FromValue)
case "*uint32":
if _, ok := input.FromValue.(*uint32); ok {
return input.FromValue
}
v := Uint32(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "uint64":
return Uint64(input.FromValue)
case "*uint64":
if _, ok := input.FromValue.(*uint64); ok {
return input.FromValue
}
v := Uint64(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "float32":
return Float32(input.FromValue)
case "*float32":
if _, ok := input.FromValue.(*float32); ok {
return input.FromValue
}
v := Float32(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "float64":
return Float64(input.FromValue)
case "*float64":
if _, ok := input.FromValue.(*float64); ok {
return input.FromValue
}
v := Float64(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "bool":
return Bool(input.FromValue)
case "*bool":
if _, ok := input.FromValue.(*bool); ok {
return input.FromValue
}
v := Bool(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "string":
return String(input.FromValue)
case "*string":
if _, ok := input.FromValue.(*string); ok {
return input.FromValue
}
v := String(input.FromValue)
return &v
2019-06-19 09:06:52 +08:00
case "[]byte":
return Bytes(input.FromValue)
2019-06-19 09:06:52 +08:00
case "[]int":
return Ints(input.FromValue)
case "[]int32":
return Int32s(input.FromValue)
case "[]int64":
return Int64s(input.FromValue)
case "[]uint":
return Uints(input.FromValue)
case "[]uint8":
return Bytes(input.FromValue)
case "[]uint32":
return Uint32s(input.FromValue)
case "[]uint64":
return Uint64s(input.FromValue)
case "[]float32":
return Float32s(input.FromValue)
case "[]float64":
return Float64s(input.FromValue)
2019-06-19 09:06:52 +08:00
case "[]string":
return Strings(input.FromValue)
2019-06-19 09:06:52 +08:00
case "Time", "time.Time":
if len(input.Extra) > 0 {
return Time(input.FromValue, String(input.Extra[0]))
2019-06-19 09:06:52 +08:00
}
return Time(input.FromValue)
case "*time.Time":
var v interface{}
if len(input.Extra) > 0 {
v = Time(input.FromValue, String(input.Extra[0]))
} else {
if _, ok := input.FromValue.(*time.Time); ok {
return input.FromValue
}
v = Time(input.FromValue)
2019-06-19 09:06:52 +08:00
}
return &v
2019-06-19 09:06:52 +08:00
case "GTime", "gtime.Time":
if len(input.Extra) > 0 {
if v := GTime(input.FromValue, String(input.Extra[0])); v != nil {
return *v
} else {
return *gtime.New()
}
}
if v := GTime(input.FromValue); v != nil {
return *v
} else {
return *gtime.New()
}
case "*gtime.Time":
if len(input.Extra) > 0 {
if v := GTime(input.FromValue, String(input.Extra[0])); v != nil {
return v
} else {
return gtime.New()
}
}
if v := GTime(input.FromValue); v != nil {
return v
} else {
return gtime.New()
2019-06-19 09:06:52 +08:00
}
case "Duration", "time.Duration":
return Duration(input.FromValue)
case "*time.Duration":
if _, ok := input.FromValue.(*time.Duration); ok {
return input.FromValue
}
v := Duration(input.FromValue)
return &v
case "map[string]string":
return MapStrStr(input.FromValue)
case "map[string]interface{}":
return Map(input.FromValue)
case "[]map[string]interface{}":
return Maps(input.FromValue)
2019-06-19 09:06:52 +08:00
default:
if input.ReferValue != nil {
var (
referReflectValue reflect.Value
)
if v, ok := input.ReferValue.(reflect.Value); ok {
referReflectValue = v
} else {
referReflectValue = reflect.ValueOf(input.ReferValue)
}
input.ToTypeName = referReflectValue.Kind().String()
input.ReferValue = nil
return reflect.ValueOf(doConvert(input)).Convert(referReflectValue.Type()).Interface()
}
return input.FromValue
2019-06-19 09:06:52 +08:00
}
}
// Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.
// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
// It supports common types conversion as its conversion based on type name string.
func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} {
return doConvert(doConvertInput{
FromValue: fromValue,
ToTypeName: toTypeName,
ReferValue: nil,
Extra: extraParams,
})
}
2021-05-17 21:26:39 +08:00
// Byte converts `any` to byte.
func Byte(any interface{}) byte {
if v, ok := any.(byte); ok {
2019-05-09 22:53:42 +08:00
return v
}
return Uint8(any)
2019-05-09 22:53:42 +08:00
}
2021-05-17 21:26:39 +08:00
// Bytes converts `any` to []byte.
func Bytes(any interface{}) []byte {
if any == nil {
2019-06-19 09:06:52 +08:00
return nil
}
switch value := any.(type) {
2019-06-19 09:06:52 +08:00
case string:
return []byte(value)
case []byte:
return value
default:
2021-03-18 15:21:05 +08:00
if f, ok := value.(apiBytes); ok {
return f.Bytes()
}
2021-05-25 09:56:23 +08:00
var (
reflectValue = reflect.ValueOf(any)
reflectKind = reflectValue.Kind()
)
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
switch reflectKind {
case reflect.Array, reflect.Slice:
var (
ok = true
bytes = make([]byte, reflectValue.Len())
)
for i, _ := range bytes {
int32Value := Int32(reflectValue.Index(i).Interface())
if int32Value < 0 || int32Value > math.MaxUint8 {
ok = false
break
}
bytes[i] = byte(int32Value)
}
if ok {
return bytes
}
}
return gbinary.Encode(any)
2019-06-19 09:06:52 +08:00
}
2018-01-03 10:23:37 +08:00
}
2021-05-17 21:26:39 +08:00
// Rune converts `any` to rune.
func Rune(any interface{}) rune {
if v, ok := any.(rune); ok {
2019-05-09 22:53:42 +08:00
return v
}
2021-05-25 09:56:23 +08:00
return Int32(any)
2019-05-09 22:53:42 +08:00
}
2021-05-17 21:26:39 +08:00
// Runes converts `any` to []rune.
func Runes(any interface{}) []rune {
if v, ok := any.([]rune); ok {
2019-05-09 22:53:42 +08:00
return v
}
return []rune(String(any))
2019-05-09 22:53:42 +08:00
}
2021-05-17 21:26:39 +08:00
// String converts `any` to string.
// It's most common used converting function.
func String(any interface{}) string {
if any == nil {
2019-06-19 09:06:52 +08:00
return ""
}
switch value := any.(type) {
2019-06-19 09:06:52 +08:00
case int:
return strconv.Itoa(value)
2019-06-19 09:06:52 +08:00
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.FormatInt(value, 10)
2019-06-19 09:06:52 +08:00
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(value, 10)
2019-06-19 09:06:52 +08:00
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)
case time.Time:
if value.IsZero() {
return ""
}
return value.String()
case *time.Time:
if value == nil {
return ""
}
return value.String()
case gtime.Time:
if value.IsZero() {
return ""
}
return value.String()
case *gtime.Time:
if value == nil {
return ""
}
return value.String()
2019-06-19 09:06:52 +08:00
default:
2020-01-03 20:23:10 +08:00
// Empty checks.
if value == nil {
return ""
}
2019-06-19 09:06:52 +08:00
if f, ok := value.(apiString); ok {
// If the variable implements the String() interface,
// then use that interface to perform the conversion
return f.String()
}
if f, ok := value.(apiError); ok {
2019-06-19 09:06:52 +08:00
// If the variable implements the Error() interface,
// then use that interface to perform the conversion
return f.Error()
}
// Reflect checks.
2020-09-18 23:59:49 +08:00
var (
rv = reflect.ValueOf(value)
kind = rv.Kind()
)
switch kind {
case reflect.Chan,
reflect.Map,
reflect.Slice,
reflect.Func,
reflect.Ptr,
reflect.Interface,
reflect.UnsafePointer:
if rv.IsNil() {
return ""
2019-07-22 15:31:35 +08:00
}
2020-09-18 23:59:49 +08:00
case reflect.String:
return rv.String()
2019-06-19 09:06:52 +08:00
}
if kind == reflect.Ptr {
return String(rv.Elem().Interface())
}
// Finally we use json.Marshal to convert.
if jsonContent, err := json.Marshal(value); err != nil {
return fmt.Sprint(value)
} else {
return string(jsonContent)
}
2019-06-19 09:06:52 +08:00
}
2017-12-31 11:09:16 +08:00
}
2021-05-17 21:26:39 +08:00
// Bool converts `any` to bool.
// It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map.
func Bool(any interface{}) bool {
if any == nil {
2019-06-19 09:06:52 +08:00
return false
}
switch value := any.(type) {
2019-07-20 16:41:17 +08:00
case bool:
return value
case []byte:
if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok {
return false
}
return true
2019-07-20 16:41:17 +08:00
case string:
if _, ok := emptyStringMap[strings.ToLower(value)]; ok {
2019-06-19 09:06:52 +08:00
return false
}
return true
default:
2021-03-18 15:21:05 +08:00
if f, ok := value.(apiBool); ok {
return f.Bool()
}
rv := reflect.ValueOf(any)
2019-07-20 16:41:17 +08:00
switch rv.Kind() {
case reflect.Ptr:
return !rv.IsNil()
case reflect.Map:
fallthrough
case reflect.Array:
fallthrough
case reflect.Slice:
return rv.Len() != 0
case reflect.Struct:
return true
default:
s := strings.ToLower(String(any))
2019-07-20 16:41:17 +08:00
if _, ok := emptyStringMap[s]; ok {
return false
}
return true
2019-06-19 09:06:52 +08:00
}
}
2017-12-31 11:09:16 +08:00
}
2021-05-17 21:26:39 +08:00
// Int converts `any` to int.
func Int(any interface{}) int {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(int); ok {
2019-06-19 09:06:52 +08:00
return v
}
return int(Int64(any))
2017-12-31 11:09:16 +08:00
}
2021-05-17 21:26:39 +08:00
// Int8 converts `any` to int8.
func Int8(any interface{}) int8 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(int8); ok {
2019-06-19 09:06:52 +08:00
return v
}
return int8(Int64(any))
}
2021-05-17 21:26:39 +08:00
// Int16 converts `any` to int16.
func Int16(any interface{}) int16 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(int16); ok {
2019-06-19 09:06:52 +08:00
return v
}
return int16(Int64(any))
}
2021-05-17 21:26:39 +08:00
// Int32 converts `any` to int32.
func Int32(any interface{}) int32 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(int32); ok {
2019-06-19 09:06:52 +08:00
return v
}
return int32(Int64(any))
}
2021-05-17 21:26:39 +08:00
// Int64 converts `any` to int64.
func Int64(any interface{}) int64 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
switch value := any.(type) {
2019-06-19 09:06:52 +08:00
case int:
return int64(value)
case int8:
return int64(value)
case int16:
return int64(value)
case int32:
return int64(value)
case int64:
return value
case uint:
return int64(value)
case uint8:
return int64(value)
case uint16:
return int64(value)
case uint32:
return int64(value)
case uint64:
return int64(value)
case float32:
return int64(value)
case float64:
return int64(value)
case bool:
if value {
return 1
}
return 0
2019-07-20 16:41:17 +08:00
case []byte:
return gbinary.DecodeToInt64(value)
2019-06-19 09:06:52 +08:00
default:
2021-03-18 15:21:05 +08:00
if f, ok := value.(apiInt64); ok {
return f.Int64()
}
2019-06-19 09:06:52 +08:00
s := String(value)
isMinus := false
2020-01-20 21:25:55 +08:00
if len(s) > 0 {
if s[0] == '-' {
isMinus = true
s = s[1:]
} else if s[0] == '+' {
s = s[1:]
}
}
2019-06-19 09:06:52 +08:00
// Hexadecimal
if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
if v, e := strconv.ParseInt(s[2:], 16, 64); e == nil {
if isMinus {
return -v
}
2019-06-19 09:06:52 +08:00
return v
}
}
// Octal
if len(s) > 1 && s[0] == '0' {
if v, e := strconv.ParseInt(s[1:], 8, 64); e == nil {
if isMinus {
return -v
}
2019-06-19 09:06:52 +08:00
return v
}
}
// Decimal
if v, e := strconv.ParseInt(s, 10, 64); e == nil {
if isMinus {
return -v
}
2019-06-19 09:06:52 +08:00
return v
}
// Float64
return int64(Float64(value))
}
}
2021-05-17 21:26:39 +08:00
// Uint converts `any` to uint.
func Uint(any interface{}) uint {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(uint); ok {
2019-06-19 09:06:52 +08:00
return v
}
return uint(Uint64(any))
}
2021-05-17 21:26:39 +08:00
// Uint8 converts `any` to uint8.
func Uint8(any interface{}) uint8 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(uint8); ok {
2019-06-19 09:06:52 +08:00
return v
}
return uint8(Uint64(any))
}
2021-05-17 21:26:39 +08:00
// Uint16 converts `any` to uint16.
func Uint16(any interface{}) uint16 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(uint16); ok {
2019-06-19 09:06:52 +08:00
return v
}
return uint16(Uint64(any))
}
2021-05-17 21:26:39 +08:00
// Uint32 converts `any` to uint32.
func Uint32(any interface{}) uint32 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
if v, ok := any.(uint32); ok {
2019-06-19 09:06:52 +08:00
return v
}
return uint32(Uint64(any))
}
2021-05-17 21:26:39 +08:00
// Uint64 converts `any` to uint64.
func Uint64(any interface{}) uint64 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
switch value := any.(type) {
2019-06-19 09:06:52 +08:00
case int:
return uint64(value)
case int8:
return uint64(value)
case int16:
return uint64(value)
case int32:
return uint64(value)
case int64:
return uint64(value)
case uint:
return uint64(value)
case uint8:
return uint64(value)
case uint16:
return uint64(value)
case uint32:
return uint64(value)
case uint64:
return value
case float32:
return uint64(value)
case float64:
return uint64(value)
case bool:
if value {
return 1
}
return 0
2019-07-20 16:41:17 +08:00
case []byte:
return gbinary.DecodeToUint64(value)
2019-06-19 09:06:52 +08:00
default:
2021-03-18 15:21:05 +08:00
if f, ok := value.(apiUint64); ok {
return f.Uint64()
}
2019-06-19 09:06:52 +08:00
s := String(value)
// Hexadecimal
if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
if v, e := strconv.ParseUint(s[2:], 16, 64); e == nil {
return v
}
}
// Octal
if len(s) > 1 && s[0] == '0' {
if v, e := strconv.ParseUint(s[1:], 8, 64); e == nil {
return v
}
}
// Decimal
if v, e := strconv.ParseUint(s, 10, 64); e == nil {
return v
}
// Float64
return uint64(Float64(value))
}
2017-12-31 11:09:16 +08:00
}
2021-05-17 21:26:39 +08:00
// Float32 converts `any` to float32.
func Float32(any interface{}) float32 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
switch value := any.(type) {
2019-07-20 16:41:17 +08:00
case float32:
return value
case float64:
return float32(value)
case []byte:
return gbinary.DecodeToFloat32(value)
default:
2021-03-18 15:21:05 +08:00
if f, ok := value.(apiFloat32); ok {
return f.Float32()
}
v, _ := strconv.ParseFloat(String(any), 64)
2019-07-20 16:41:17 +08:00
return float32(v)
2019-06-19 09:06:52 +08:00
}
2017-12-31 11:09:16 +08:00
}
2021-05-17 21:26:39 +08:00
// Float64 converts `any` to float64.
func Float64(any interface{}) float64 {
if any == nil {
2019-06-19 09:06:52 +08:00
return 0
}
switch value := any.(type) {
2019-07-20 16:41:17 +08:00
case float32:
return float64(value)
case float64:
return value
case []byte:
return gbinary.DecodeToFloat64(value)
default:
2021-03-18 15:21:05 +08:00
if f, ok := value.(apiFloat64); ok {
return f.Float64()
}
v, _ := strconv.ParseFloat(String(any), 64)
2019-06-19 09:06:52 +08:00
return v
}
2017-12-31 11:09:16 +08:00
}