Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 在Struct中的字符串字段上迭代_Go - Fatal编程技术网

Go 在Struct中的字符串字段上迭代

Go 在Struct中的字符串字段上迭代,go,Go,我希望迭代结构的字符串字段,以便进行一些清理/验证(使用strings.TrimSpace,strings.Trim等) 现在我有一个乱七八糟的开关盒,它不是真正可伸缩的,而且由于它不在我的应用程序(web表单)的热点中,因此利用reflect似乎是一个不错的选择 然而,在如何实现这一点上,我遇到了一些障碍,而reflect文档让我有点困惑(我一直在挖掘其他一些验证包,但它们太重了+我已经在使用gorilla/schema进行解组): 在结构上迭代 对于字符串类型的每个字段,应用strings

我希望迭代结构的字符串字段,以便进行一些清理/验证(使用
strings.TrimSpace
strings.Trim
等)

现在我有一个乱七八糟的开关盒,它不是真正可伸缩的,而且由于它不在我的应用程序(web表单)的热点中,因此利用
reflect
似乎是一个不错的选择

然而,在如何实现这一点上,我遇到了一些障碍,而reflect文档让我有点困惑(我一直在挖掘其他一些验证包,但它们太重了+我已经在使用gorilla/schema进行解组):

  • 在结构上迭代
  • 对于字符串类型的每个字段,应用
    strings
    包中需要的任何内容,即
    field=strings.TrimSpace(field)
  • 如果存在field.Tag.Get(“max”),我们将使用该值(strconv.Atoi,然后是unicode.runecounnstring)
  • 提供一个也与错误接口类型兼容的错误片

    type FormError []string         
    
    type Listing struct {
            Title string `max:"50"`
            Location string `max:"100"`
            Description string `max:"10000"`
            ExpiryDate time.Time
            RenderedDesc template.HTML
            Contact string `max:"255"`
        }
    
        // Iterate over our struct, fix whitespace/formatting where possible
        // and return errors encountered
        func (l *Listing) Validate() error {
    
           typ := l.Elem().Type()
    
           var invalid FormError
           for i = 0; i < typ.NumField(); i++ {
               // Iterate over fields
               // For StructFields of type string, field = strings.TrimSpace(field)
               // if field.Tag.Get("max") != "" {
               //     check max length/convert to int/utf8.RuneCountInString
                      if max length exceeded, invalid = append(invalid, "errormsg")
           }
    
           if len(invalid) > 0 {
               return invalid
           } 
    
           return nil
       }
    
    
       func (f FormError) Error() string {
           var fullError string
           for _, v := range f {
               fullError =+ v + "\n"
           }
           return "Errors were encountered during form processing: " + fullError
       }
    
    type FormError[]字符串
    类型列表结构{
    标题字符串`max:“50”`
    位置字符串`max:“100”`
    说明字符串`max:“10000”`
    呼气时间,时间
    renderedesc template.HTML
    联系人字符串`max:“255”`
    }
    //迭代我们的结构,尽可能修复空白/格式
    //并返回遇到的错误
    func(l*列表)Validate()错误{
    类型:=l.Elem().Type()
    var无效FormError
    对于i=0;i0{
    返回无效
    } 
    归零
    }
    func(f FormError)Error()字符串{
    var fullError字符串
    对于u,v:=范围f{
    fullError=+v+“\n”
    }
    return“表单处理过程中遇到错误:”+fullError
    }
    

提前感谢。

您需要的主要是reflect.Value上名为
NumFields()int
Field(int)
的方法。唯一缺少的是字符串检查和
SetString
方法

package main

import "fmt"
import "reflect"
import "strings"

type MyStruct struct {
    A,B,C string
    I int
    D string
    J int
}

func main() {
    ms := MyStruct{"Green ", " Eggs", " and ", 2, " Ham      ", 15}
    // Print it out now so we can see the difference
    fmt.Printf("%s%s%s%d%s%d\n", ms.A, ms.B, ms.C, ms.I, ms.D, ms.J)

    // We need a pointer so that we can set the value via reflection
    msValuePtr := reflect.ValueOf(&ms)
    msValue := msValuePtr.Elem()

    for i := 0; i < msValue.NumField(); i++ {
        field := msValue.Field(i)

        // Ignore fields that don't have the same type as a string
        if field.Type() != reflect.TypeOf("") {
            continue
        }

        str := field.Interface().(string)
        str = strings.TrimSpace(str)
        field.SetString(str)
    }
    fmt.Printf("%s%s%s%d%s%d\n", ms.A, ms.B, ms.C, ms.I, ms.D, ms.J)
}
主程序包
输入“fmt”
导入“反映”
导入“字符串”
类型MyStruct struct{
A、 B,C字符串
I int
D字符串
J int
}
func main(){
ms:=我的结构{“绿色”、“鸡蛋”、“和”,2,“火腿”,15}
//现在把它打印出来,这样我们就可以看到区别了
fmt.Printf(“%s%s%s%d%s%d\n”,女士A、女士B、女士C、女士I、女士d、女士J)
//我们需要一个指针,以便通过反射设置值
msValuePtr:=reflect.ValueOf(&ms)
msValue:=msValuePtr.Elem()
对于i:=0;i

这里有两个警告:

  • 您需要一个指向要更改内容的指针。如果有值,则需要返回修改后的结果

  • 试图修改未报告的字段通常会导致reflect恐慌。如果您计划修改未报告的字段,请确保在包内执行此操作

  • 这段代码相当灵活,如果您需要不同的行为(取决于类型),可以使用switch语句或类型开关(根据field.Interface()返回的值)

    编辑:至于标记行为,您似乎已经知道了。一旦您有了字段并检查它是否是字符串,您就可以使用
    field.tag.Get(“max”)
    并从那里解析它

    Edit2:我在标记上犯了一个小错误。标记是结构的reflect.Type的一部分,所以要获取它们,可以使用(这有点冗长)
    msValue.Type().Field(I).tag.get(“max”)


    (您在评论中发布的代码,带有一个工作标记get)。

    我被打败了,但自从我开始工作后,这里有一个解决方案:

    type FormError []*string
    
    type Listing struct {
        Title        string `max:"50"`
        Location     string `max:"100"`
        Description  string `max:"10000"`
        ExpiryDate   time.Time
        RenderedDesc template.HTML
        Contact      string `max:"255"`
    }
    
    // Iterate over our struct, fix whitespace/formatting where possible
    // and return errors encountered
    func (l *Listing) Validate() error {
        listingType := reflect.TypeOf(*l)
        listingValue := reflect.ValueOf(l)
        listingElem := listingValue.Elem()
    
        var invalid FormError = []*string{}
        // Iterate over fields
        for i := 0; i < listingElem.NumField(); i++ {
            fieldValue := listingElem.Field(i)
            // For StructFields of type string, field = strings.TrimSpace(field)
            if fieldValue.Type().Name() == "string" {
                newFieldValue := strings.TrimSpace(fieldValue.Interface().(string))
                fieldValue.SetString(newFieldValue)
    
                fieldType := listingType.Field(i)
                maxLengthStr := fieldType.Tag.Get("max")
                if maxLengthStr != "" {
                    maxLength, err := strconv.Atoi(maxLengthStr)
                    if err != nil {
                        panic("Field 'max' must be an integer")
                    }
                    //     check max length/convert to int/utf8.RuneCountInString
                    if utf8.RuneCountInString(newFieldValue) > maxLength {
                        //     if max length exceeded, invalid = append(invalid, "errormsg")
                        invalidMessage := `"`+fieldType.Name+`" is too long (max allowed: `+maxLengthStr+`)`
                        invalid = append(invalid, &invalidMessage)
                    }
                }
            }
        }
    
        if len(invalid) > 0 {
            return invalid
        }
    
        return nil
    }
    
    func (f FormError) Error() string {
        var fullError string
        for _, v := range f {
            fullError = *v + "\n"
        }
        return "Errors were encountered during form processing: " + fullError
    }
    
    键入FormError[]*字符串
    类型列表结构{
    标题字符串`max:“50”`
    位置字符串`max:“100”`
    说明字符串`max:“10000”`
    呼气时间,时间
    renderedesc template.HTML
    联系人字符串`max:“255”`
    }
    //迭代我们的结构,尽可能修复空白/格式
    //并返回遇到的错误
    func(l*列表)Validate()错误{
    listingType:=reflect.TypeOf(*l)
    listingValue:=反射值(l)
    listingElem:=listingValue.Elem()
    var无效FormError=[]*字符串{}
    //在字段上迭代
    对于i:=0;imaxLength{
    //如果超过最大长度,则无效=追加(无效,“errormsg”)
    
    trimStruct(&someStruct)
    
    func trimStruct(v interface{}) {
        bytes, err := json.Marshal(v)
        if err != nil {
            fmt.Println("[trimStruct] Marshal Error :", err)
        }
        var mapSI map[string]interface{}
        if err := json.Unmarshal(bytes, &mapSI); err != nil {
            fmt.Println("[trimStruct] Unmarshal to byte Error :", err)
        }
        mapSI = trimMapStringInterface(mapSI).(map[string]interface{})
        bytes2, err := json.Marshal(mapSI)
        if err != nil {
            fmt.Println("[trimStruct] Marshal Error :", err)
        }
        if err := json.Unmarshal(bytes2, v); err != nil {
            fmt.Println("[trimStruct] Unmarshal to b Error :", err)
        }
    }
    
    func trimMapStringInterface(data interface{}) interface{} {
        if values, valid := data.([]interface{}); valid {
            for i := range values {
                data.([]interface{})[i] = trimMapStringInterface(values[i])
            }
        } else if values, valid := data.(map[string]interface{}); valid {
            for k, v := range values {
                data.(map[string]interface{})[k] = trimMapStringInterface(v)
            }
        } else if value, valid := data.(string); valid {
            data = strings.TrimSpace(value)
        }
        return data
    }