Go使用反射递归复制结构体

前言

go初学,今天本来有个需求涉及到用反射,然后花了时间边学边做,嗯,做完了之后发现做复杂了。缘由如下,有个结构体不能直接用,需要对里面的字段做一下调整,但是考虑到这个结构体里的字段会经常做一些变动,所以就想着使用反射自动化复制一份出来,并对需要调整的字段进行调整,以后再有增减字段,直接执行脚本就可以同步改动了。还是太天真,下面的例子是做了简化的例子,就瞎写,大家凑合看吧。

结构

Go使用反射递归复制结构体

 

 

 1. common里放的生成的结果。

2. scripts里的generate.go是实现,里面有一个main方法供脚本调用

3. scripts里的bash.sh是调用脚本。

4. struct.go里是要复制的结构体样本。

代码

struct.go

package reflectLearning

type Student struct {
	Name  string  `json:"name"`
	Age   int64   `json:"age"`
	Body  *Body   `json:"body"`
	Bodys []*Body `json:"bodys"`  // 这里单纯是为了多样化
}

type Body struct {
	Height int64 `json:"height"`
	Weight int64 `json:"weight"`
}
Go使用反射递归复制结构体
package main

import (
    "bufio"
    "fmt"
    "goLearning/reflectLearning"
    "os"
    "reflect"
    "strings"
)

var (
    voucherProtos = []reflect.Type{
        reflect.TypeOf(reflectLearning.Student{}),
    }
)
var baseTypes = map[reflect.Kind]bool{
    reflect.Bool:    true,
    reflect.Int:     true,
    reflect.Int8:    true,
    reflect.Int16:   true,
    reflect.Int32:   true,
    reflect.Int64:   true,
    reflect.Uint:    true,
    reflect.Uint8:   true,
    reflect.Uint16:  true,
    reflect.Uint32:  true,
    reflect.Uint64:  true,
    reflect.Uintptr: true,
    reflect.Float32: true,
    reflect.Float64: true,
    reflect.Map:     true,
    reflect.String:  true,
}

func main() {
    fmt.Println("123")
    var voucherStructs = "package common\n"
    for _, proto := range voucherProtos {
        str := generateStructByType("", proto)
        voucherStructs += str
    }

    file, err := os.Create("../../common/request.go")
    if err != nil {
        fmt.Println("文件打开失败", err)
    }
    //及时关闭file句柄
    defer file.Close()
    //写入文件时,使用带缓存的 *Writer
    write := bufio.NewWriter(file)
    write.WriteString(voucherStructs)
    //Flush将缓存的文件真正写入到文件中
    write.Flush()
}

func generateStructByType(content string, tp reflect.Type) string {
    str := fmt.Sprintf("type %s struct {\n", tp.Name())
    if i := strings.IndexAny(content, str); i != -1 { // 避免重复生成结构体
        return ""
    }
    var voucherStructs string

    // 遍历结构体的所有字段
    for i := 0; i < tp.NumField(); i++ {
        field := tp.Field(i)

        if baseTypes[field.Type.Kind()] { // 基础类型

            fieldType := field.Type.Name()
            if field.Name == "VoucherID" {
                fieldType = "string"
            }
            str += fmt.Sprintf("%s %s `%s`\n", field.Name, fieldType, field.Tag)
        } else if field.Type.Kind() == reflect.Ptr { // 指针类型

            pointType := field.Type.Elem()    // 指针指向的类型
            if !baseTypes[pointType.Kind()] { // 不是基础类型则认为是结构体,递归生成结构体
                voucherStructs += generateStructByType(voucherStructs, pointType)
            }
            str += fmt.Sprintf("%s *%s `%s`\n", field.Name, pointType.Name(), field.Tag)

        } else if field.Type.Kind() == reflect.Slice { // 数组,分为基本类型数组,结构体数组,指针基本类型数据,指针结构体数组
            fieldType := "[]"
            ele := field.Type.Elem()
            // 先判断是不是指针数组
            if ele.Kind() == reflect.Ptr {
                fieldType += "*"
                // 指针类型是基本类型还是结构体
                subEle := ele.Elem()
                if baseTypes[subEle.Kind()] { // 基本类型

                    fieldType += subEle.Name() // 结构体
                } else {
                    voucherStructs += generateStructByType(voucherStructs, subEle)
                    str += fmt.Sprintf("%s *%s `%s`\n", field.Name, subEle.Name(), field.Tag)
                }
            }

        }
    }
    str += "}\n"
    voucherStructs = voucherStructs + str

    return voucherStructs
}
View Code

 

 

generate.go

 

上一篇:Golang中的反射机制


下一篇:golang利用反射写入excel的简单工具类