我在寻找一个struct的字符串字段遍历,所以我可以做一些清理/验证(与strings.TrimSpace,strings.Trim等)。
strings.TrimSpace
strings.Trim
现在,我有一个混乱的开关盒,它并没有真正的可扩展性,而且由于这并不是我的应用程序(Web表单)的热点,因此reflect在这里利用杠杆作用似乎是一个不错的选择。
reflect
我对于如何实现此功能有点障碍,反射文档对我来说有点困惑(我一直在研究其他一些验证包,但是它们太笨重了,我正在使用大猩猩/模式已用于解组部分):
strings
field = strings.TrimSpace(field)
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 }
提前致谢。
您想要的主要是reflect.Value上称为NumFields() int和的方法Field(int)。您唯一真正缺少的是字符串检查和SetString方法。
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) }
(游乐场链接)
这里有两个警告:
您需要一个指向要更改的指针。如果有值,则需要返回修改后的结果。
尝试修改未导出的字段通常会引起反射恐慌。如果您打算修改未导出的字段,请确保在包内执行此操作。
该代码相当灵活,如果您需要根据类型的不同行为,则可以使用switch语句或类型switch(在field.Interface()返回的值上)。
编辑:至于标记行为,您似乎已经知道了。一旦有了字段并检查了它是否是字符串,就可以field.Tag.Get("max")从那里使用并解析它。
field.Tag.Get("max")
Edit2:我在标签上犯了一个小错误。标签是反射类型的一部分。结构的类型,因此可以使用它们(有点麻烦)msValue.Type().Field(i).Tag.Get("max")
msValue.Type().Field(i).Tag.Get("max")
(您在注释中发布的带有有效Tag的代码的Playground版本)。