improve String/Map converting for package gconv

This commit is contained in:
John
2020-04-07 21:29:41 +08:00
parent 01995f5501
commit 25a91c732c
2 changed files with 190 additions and 190 deletions

View File

@ -231,35 +231,35 @@ func String(i interface{}) string {
// If the variable implements the String() interface,
// then use that interface to perform the conversion
return f.String()
} else if f, ok := value.(apiError); ok {
}
if f, ok := value.(apiError); ok {
// If the variable implements the Error() interface,
// then use that interface to perform the conversion
return f.Error()
}
// Reflect checks.
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 ""
}
}
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 {
// Reflect checks.
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 ""
}
}
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)
}
return string(jsonContent)
}
}
}

View File

@ -45,192 +45,192 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]
if value == nil {
return nil
}
if r, ok := value.(map[string]interface{}); ok {
// Assert the common combination of types, and finally it uses reflection.
m := make(map[string]interface{})
switch r := value.(type) {
case string:
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.Unmarshal([]byte(r), &m); err != nil {
return nil
}
} else {
return nil
}
case []byte:
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.Unmarshal(r, &m); err != nil {
return nil
}
} else {
return nil
}
case map[interface{}]interface{}:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]string:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]int:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]uint:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]float32:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]float64:
for k, v := range r {
m[String(k)] = v
}
case map[string]bool:
for k, v := range r {
m[k] = v
}
case map[string]int:
for k, v := range r {
m[k] = v
}
case map[string]uint:
for k, v := range r {
m[k] = v
}
case map[string]float32:
for k, v := range r {
m[k] = v
}
case map[string]float64:
for k, v := range r {
m[k] = v
}
case map[string]interface{}:
return r
} else {
// Assert the common combination of types, and finally it uses reflection.
m := make(map[string]interface{})
switch r := value.(type) {
case string:
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.Unmarshal([]byte(r), &m); err != nil {
return nil
case map[int]interface{}:
for k, v := range r {
m[String(k)] = v
}
case map[int]string:
for k, v := range r {
m[String(k)] = v
}
case map[uint]string:
for k, v := range r {
m[String(k)] = v
}
// Not a common type, it then uses reflection for conversion.
default:
rv := reflect.ValueOf(value)
kind := rv.Kind()
// If it is a pointer, we should find its real data type.
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
// If <value> is type of array, it converts the value of even number index as its key and
// the value of odd number index as its corresponding value.
// Eg:
// []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
// []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
case reflect.Slice, reflect.Array:
length := rv.Len()
for i := 0; i < length; i += 2 {
if i+1 < length {
m[String(rv.Index(i).Interface())] = rv.Index(i + 1).Interface()
} else {
m[String(rv.Index(i).Interface())] = nil
}
} else {
return nil
}
case []byte:
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.Unmarshal(r, &m); err != nil {
return nil
case reflect.Map:
ks := rv.MapKeys()
for _, k := range ks {
m[String(k.Interface())] = rv.MapIndex(k).Interface()
}
case reflect.Struct:
// Map converting interface check.
if v, ok := value.(apiMapStrAny); ok {
return v.MapStrAny()
}
// Using reflect for converting.
rt := rv.Type()
name := ""
tagArray := structTagPriority
switch len(tags) {
case 0:
// No need handle.
case 1:
tagArray = append(strings.Split(tags[0], ","), structTagPriority...)
default:
tagArray = append(tags, structTagPriority...)
}
var rtField reflect.StructField
var rvField reflect.Value
var rvKind reflect.Kind
for i := 0; i < rv.NumField(); i++ {
rtField = rt.Field(i)
rvField = rv.Field(i)
// Only convert the public attributes.
fieldName := rtField.Name
if !utils.IsLetterUpper(fieldName[0]) {
continue
}
} else {
return nil
}
case map[interface{}]interface{}:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]string:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]int:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]uint:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]float32:
for k, v := range r {
m[String(k)] = v
}
case map[interface{}]float64:
for k, v := range r {
m[String(k)] = v
}
case map[string]bool:
for k, v := range r {
m[k] = v
}
case map[string]int:
for k, v := range r {
m[k] = v
}
case map[string]uint:
for k, v := range r {
m[k] = v
}
case map[string]float32:
for k, v := range r {
m[k] = v
}
case map[string]float64:
for k, v := range r {
m[k] = v
}
case map[int]interface{}:
for k, v := range r {
m[String(k)] = v
}
case map[int]string:
for k, v := range r {
m[String(k)] = v
}
case map[uint]string:
for k, v := range r {
m[String(k)] = v
}
// Not a common type, it then uses reflection for conversion.
default:
rv := reflect.ValueOf(value)
kind := rv.Kind()
// If it is a pointer, we should find its real data type.
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
// If <value> is type of array, it converts the value of even number index as its key and
// the value of odd number index as its corresponding value.
// Eg:
// []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
// []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
case reflect.Slice, reflect.Array:
length := rv.Len()
for i := 0; i < length; i += 2 {
if i+1 < length {
m[String(rv.Index(i).Interface())] = rv.Index(i + 1).Interface()
} else {
m[String(rv.Index(i).Interface())] = nil
name = ""
fieldTag := rtField.Tag
for _, tag := range tagArray {
if name = fieldTag.Get(tag); name != "" {
break
}
}
case reflect.Map:
ks := rv.MapKeys()
for _, k := range ks {
m[String(k.Interface())] = rv.MapIndex(k).Interface()
}
case reflect.Struct:
// Map converting interface check.
if v, ok := value.(apiMapStrAny); ok {
return v.MapStrAny()
}
rt := rv.Type()
name := ""
tagArray := structTagPriority
switch len(tags) {
case 0:
// No need handle.
case 1:
tagArray = append(strings.Split(tags[0], ","), structTagPriority...)
default:
tagArray = append(tags, structTagPriority...)
}
var rtField reflect.StructField
var rvField reflect.Value
var rvKind reflect.Kind
for i := 0; i < rv.NumField(); i++ {
rtField = rt.Field(i)
rvField = rv.Field(i)
// Only convert the public attributes.
fieldName := rtField.Name
if !utils.IsLetterUpper(fieldName[0]) {
if name == "" {
name = strings.TrimSpace(fieldName)
} else {
// Support json tag feature: -, omitempty
name = strings.TrimSpace(name)
if name == "-" {
continue
}
name = ""
fieldTag := rtField.Tag
for _, tag := range tagArray {
if name = fieldTag.Get(tag); name != "" {
break
}
}
if name == "" {
name = strings.TrimSpace(fieldName)
} else {
// Support json tag feature: -, omitempty
name = strings.TrimSpace(name)
if name == "-" {
continue
}
array := strings.Split(name, ",")
if len(array) > 1 {
switch strings.TrimSpace(array[1]) {
case "omitempty":
if empty.IsEmpty(rvField.Interface()) {
continue
} else {
name = strings.TrimSpace(array[0])
}
default:
array := strings.Split(name, ",")
if len(array) > 1 {
switch strings.TrimSpace(array[1]) {
case "omitempty":
if empty.IsEmpty(rvField.Interface()) {
continue
} else {
name = strings.TrimSpace(array[0])
}
default:
name = strings.TrimSpace(array[0])
}
}
if recursive {
}
if recursive {
rvKind = rvField.Kind()
if rvKind == reflect.Ptr {
rvField = rvField.Elem()
rvKind = rvField.Kind()
if rvKind == reflect.Ptr {
rvField = rvField.Elem()
rvKind = rvField.Kind()
}
if rvKind == reflect.Struct {
for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) {
m[k] = v
}
} else {
m[name] = rvField.Interface()
}
if rvKind == reflect.Struct {
for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) {
m[k] = v
}
} else {
m[name] = rvField.Interface()
}
} else {
m[name] = rvField.Interface()
}
default:
return nil
}
default:
return nil
}
return m
}
return m
}
// MapStrStr converts <value> to map[string]string.