问题:下面定义Student和Teacher两个结构体,如何让他们的数据值转换呢?
type Student struct { Id int `json:"id"` Name string `json:"name"` Slic []int `json:"slic"` S struct { Id int `json:"id"` Name string `json:"name"` } `json:"s"` } type Teacher struct { Id int `json:"id"` Name string `json:"name"` Slic []int `json:"slic"` S struct { Id int `json:"id"` Name string `json:"name"` } `json:"s"` }
小问题,还可以很优雅:
// StructToStruct 结构体转结构体 func StructToStruct(sourceStruct, targetStruct interface{}, cover bool) (err error) { sourceType := reflect.TypeOf(sourceStruct) targetType := reflect.TypeOf(targetStruct) if targetType.Kind() != reflect.Ptr { err = errors.New("转换失败,目标结构体不是指针") return } for sourceType.Kind() == reflect.Ptr { sourceType = sourceType.Elem() } for targetType.Kind() == reflect.Ptr { targetType = targetType.Elem() } if sourceType.Kind() != reflect.Struct || targetType.Kind() != reflect.Struct { err = errors.New("转换失败,只支持转结构体") return } sourceValue := reflect.ValueOf(sourceStruct) targetValue := reflect.ValueOf(targetStruct) for sourceValue.Kind() == reflect.Ptr { sourceValue = sourceValue.Elem() } for targetValue.Kind() == reflect.Ptr { targetValue = targetValue.Elem() } ok := transformation(sourceType, targetType, sourceValue, targetValue, cover) if !ok { err = errors.New("未转换") } return } func transformation(sourceType, targetType reflect.Type, sourceValue, targetValue reflect.Value, cover bool) (isSet bool) { for sourceType.Kind() == reflect.Ptr { sourceType = sourceType.Elem() } for targetType.Kind() == reflect.Ptr { targetType = targetType.Elem() } for sourceValue.Kind() == reflect.Ptr { sourceValue = sourceValue.Elem() } for targetValue.Kind() == reflect.Ptr { targetValue = targetValue.Elem() } // 获取目标字段,只获取不为0,且可设置的字段 var targetMap = make(map[string]int, targetValue.NumField()) for i := 0; i < targetValue.NumField(); i++ { if !targetValue.Field(i).CanSet() { continue } if !cover && !isBlank(targetValue.Field(i)) { continue } targetMap[getFieldName(targetType.Field(i))] = i } if len(targetMap) == 0 { return } // 获取源数据字段 var sourceMap = make(map[string]int, sourceType.NumField()) for i := 0; i < sourceType.NumField(); i++ { name := getFieldName(sourceType.Field(i)) if _, ok := targetMap[name]; !ok { continue } sourceMap[getFieldName(sourceType.Field(i))] = i } for name, source := range sourceMap { target, ok := targetMap[name] if !ok { continue } // 不支持往下层走,后面再补充 if sourceValue.Field(source).Kind() == reflect.Ptr || sourceValue.Field(source).Kind() == reflect.Struct { ok = transformation(sourceType.Field(source).Type, targetType.Field(target).Type, sourceValue.Field(source), targetValue.Field(target), cover) if ok { if !isSet { isSet = true } continue } } if sourceType.Field(source).Type != targetType.Field(target).Type { continue } targetValue.Field(target).Set(sourceValue.Field(source)) isSet = true } return } // 获取字段tag或者name func getFieldName(t reflect.StructField) string { s := t.Tag.Get("gorm") if s != "" { s1 := strings.Split(s, ";") for i := range s1 { if strings.HasPrefix(s1[i], "column:") { s = strings.TrimSpace(s1[i][6:]) break } } if s != "" { return s } } s = t.Tag.Get("json") if s != "" { return s } return t.Name } // 判断反射的值是否为0 func isBlank(value reflect.Value) bool { switch value.Kind() { case reflect.String: return value.Len() == 0 case reflect.Bool: return !value.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return value.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return value.Uint() == 0 case reflect.Float32, reflect.Float64: return value.Float() == 0 case reflect.Interface, reflect.Ptr: return value.IsNil() } return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface()) }