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;i
0{ 返回无效 } 归零 } 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
这里有两个警告:
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
}