• 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())
    }
    

      

  • 相关阅读:
    Cleve Moler MATLAB 创始人金秋10月中国大学校园行
    [原]ASP.NET中使用JQUERYEASYUI后,解决ClientScript.RegisterStartupScript 所注册脚本执行两次
    [原]ASP.NET中使用后端代码注册脚本 生成JQUERYEASYUI 的界面错位
    [原]jqueryeasyui 关闭tab如何自动切换到前一个tab
    [原创]C# 实例Oracle 备份,带进度提示
    停止Oracle 服务开机自动重启
    最新县及县以上行政区划代码(截止2009年12月31日)
    单元测试学习:无返回值,触发委托
    [笔记]GetRequestStream()超时问题(出现假死,卡住)
    asp.net 页面 css中图片不存在引发的异常
  • 原文地址:https://www.cnblogs.com/hardykay/p/16177265.html
Copyright © 2020-2023  润新知