对象上的 golang 补丁字符串值,递归过滤

golang patch string values on an object, recursive with filtering

社区,

使命

基本

实施 func 修补 objects

上的所有 string 字段

详情

// 更新 - 删除旧代码

解决方案

结构

更新了要使用的结构(尽管这不会影响实际程序,我使用它是为了完整性

type Tag struct {
    Name    string  `process:"yes,TagName"`
    NamePtr *string `process:"no,TagNamePtr"`
}

type User struct {
    ID           int
    Nick         string
    Name         string    `process:"yes,UserName"`
    NamePtr      *string   `process:"yes,UserNamePtr"`
    Slice        []string  `process:"yes,Slice"`
    SlicePtr     []*string `process:"yes,SlicePtr"`
    SubStruct    []Tag     `process:"yes,SubStruct"`
    SubStructPtr []*Tag    `process:"yes,SubStructPtr"`
}

辅助函数

此外,我们需要两个辅助函数来检查 struct 是否有 tag 以及 printconsole

func Stringify(i interface{}) string {
    s, _ := json.MarshalIndent(i, "", " ")
    return string(s)
}

func HasTag(structFiled reflect.StructField, tagName string, tagValue string) bool {
    tag := structFiled.Tag
    if value, ok := tag.Lookup(tagName); ok {
        parts := strings.Split(value, ",")
        if len(parts) > 0 {
            return parts[0] == tagValue
        }
    }
    return false
}

patcher - 实际解决方案

type Patcher struct {
    Matcher func(structFiled *reflect.StructField, v reflect.Value) bool
    Process func(in string) string
}

func (p *Patcher) value(idx int, v reflect.Value, structFiled *reflect.StructField) {
    if !v.IsValid() {
        return
    }
    switch v.Kind() {
    case reflect.Ptr:
        p.value(idx, v.Elem(), structFiled)
    case reflect.Struct:
        for i := 0; i < v.NumField(); i++ {
            var sf = v.Type().Field(i)
            structFiled = &sf
            p.value(i, v.Field(i), structFiled)
        }
    case reflect.Slice:
        for i := 0; i < v.Len(); i++ {
            p.value(i, v.Index(i), structFiled)
        }
    case reflect.String:
        if p.Matcher(structFiled, v) {
            v.SetString(p.Process(v.String()))
        }
    }
}

func (p *Patcher) Apply(in interface{}) {
    p.value(-1, reflect.ValueOf(in).Elem(), nil)
}

如何使用

func main() {
    var NamePtr string = "golang"
    var SubNamePtr string = "*secure"
    testUser := User{
        ID:      1,
        Name:    "lumo",
        NamePtr: &NamePtr,
        SubStruct: []Tag{{
            Name: "go",
        },
        },
        SubStructPtr: []*Tag{&Tag{
            Name:    "*go",
            NamePtr: &SubNamePtr,
        },
        },
    }

    var p = Patcher{
        // filter - return true if the field in struct has a tag process=true
        Matcher: func(structFiled *reflect.StructField, v reflect.Value) bool {
            return HasTag(*structFiled, "process", "yes")
        },
        // process
        Process: func(in string) string {
            if in != "" {
                return fmt.Sprintf("!%s!", strings.ToUpper(in))
            } else {
                return "!empty!"
            }
            return in
        },
    }

    p.Apply(&testUser)
    fmt.Println("Output:")
    fmt.Println(Stringify(testUser))
}

去玩

https://goplay.tools/snippet/-0MHDfKr7ax