Go语言不同结构体相同字段名,进行值转换

2022/4/22 6:12:53

本文主要是介绍Go语言不同结构体相同字段名,进行值转换,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

问题:下面定义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())
}

  

 



这篇关于Go语言不同结构体相同字段名,进行值转换的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程