发布于 3年前

Go语言把map接口转换为google.protobuf.Struct

以下是go语言把map[string]interface{}转换为google.protobuf.Struct:

package pb
import (
    "fmt"
    "reflect"
    st "github.com/golang/protobuf/ptypes/struct"
)
// ToStruct转换map[string]interface{} 为ptypes.Struct
func ToStruct(v map[string]interface{}) *st.Struct {
    size := len(v)
    if size == 0 {
        return nil
    }
    fields := make(map[string]*st.Value, size)
    for k, v := range v {
        fields[k] = ToValue(v)
    }
    return &st.Struct{
        Fields: fields,
    }
}
// ToValue 转换interface{} 为ptypes.Value
func ToValue(v interface{}) *st.Value {
    switch v := v.(type) {
    case nil:
        return nil
    case bool:
        return &st.Value{
            Kind: &st.Value_BoolValue{
                BoolValue: v,
            },
        }
    case int:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case int8:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case int32:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case int64:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case uint:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case uint8:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case uint32:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case uint64:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case float32:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v),
            },
        }
    case float64:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: v,
            },
        }
    case string:
        return &st.Value{
            Kind: &st.Value_StringValue{
                StringValue: v,
            },
        }
    case error:
        return &st.Value{
            Kind: &st.Value_StringValue{
                StringValue: v.Error(),
            },
        }
    default:
        // 回退为其他类型
        return toValue(reflect.ValueOf(v))
    }
}
func toValue(v reflect.Value) *st.Value {
    switch v.Kind() {
    case reflect.Bool:
        return &st.Value{
            Kind: &st.Value_BoolValue{
                BoolValue: v.Bool(),
            },
        }
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v.Int()),
            },
        }
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: float64(v.Uint()),
            },
        }
    case reflect.Float32, reflect.Float64:
        return &st.Value{
            Kind: &st.Value_NumberValue{
                NumberValue: v.Float(),
            },
        }
    case reflect.Ptr:
        if v.IsNil() {
            return nil
        }
        return toValue(reflect.Indirect(v))
    case reflect.Array, reflect.Slice:
        size := v.Len()
        if size == 0 {
            return nil
        }
        values := make([]*st.Value, size)
        for i := 0; i < size; i++ {
            values[i] = toValue(v.Index(i))
        }
        return &st.Value{
            Kind: &st.Value_ListValue{
                ListValue: &st.ListValue{
                    Values: values,
                },
            },
        }
    case reflect.Struct:
        t := v.Type()
        size := v.NumField()
        if size == 0 {
            return nil
        }
        fields := make(map[string]*st.Value, size)
        for i := 0; i < size; i++ {
            name := t.Field(i).Name
            if len(name) > 0 && 'A' <= name[0] && name[0] <= 'Z' {
                fields[name] = toValue(v.Field(i))
            }
        }
        if len(fields) == 0 {
            return nil
        }
        return &st.Value{
            Kind: &st.Value_StructValue{
                StructValue: &st.Struct{
                    Fields: fields,
                },
            },
        }
    case reflect.Map:
        keys := v.MapKeys()
        if len(keys) == 0 {
            return nil
        }
        fields := make(map[string]*st.Value, len(keys))
        for _, k := range keys {
            if k.Kind() == reflect.String {
                fields[k.String()] = toValue(v.MapIndex(k))
            }
        }
        if len(fields) == 0 {
            return nil
        }
        return &st.Value{
            Kind: &st.Value_StructValue{
                StructValue: &st.Struct{
                    Fields: fields,
                },
            },
        }
    default:
        // 最后排序
        return &st.Value{
            Kind: &st.Value_StringValue{
                StringValue: fmt.Sprint(v),
            },
        }
    }
}
©2020 edoou.com   京ICP备16001874号-3