// 堆代码 duidaima.com type Student struct { Age int `validate:"min=18"` Name string `validate:"required"` } func main() { s := Student{Age: 90, Name: "John"} err := Validate(s) if err != nil { fmt.Println(err) } }在这个示例中,我们有一个名为 Student 的结构体。该结构体有一个叫做 "Age" 的字段,该字段有一个结构标签 min=18,将最小年龄限制设定为 18 岁。
// create a student which violates age validation student := Student{Age: 17, Name: "Aiden"} func Validate(s interface{}) { // get the value of interface{}/ pointer point to val := reflect.Indirect(reflect.ValueOf(s)) }为了将学生结构体转换为 reflect.Value 对象,我们使用 reflect.ValueOf(student) 方法。然而,由于我们不知道传入的参数 s 是指针、接口还是简单的结构体,我们使用 reflect.Indirect() 方法来确保我们得到结构体的正确值。
for i := 0; i < val.NumField(); i++ { typeField := val.Type().Field(i) // get field i-th of type(val) tag := typeField.Tag.Get("validate") if tag == "" { continue } fmt.Println(tag) } // min=18 // required3. 一旦我们得到了验证代码,剩下的任务就是处理和应用它。
// get the value of field like 17 or "Aiden" valueField := val.Field(i) // split the tag so we can use like this: `required:"limit=20" rules := strings.Split(tag, ",") for _, rule := range rules { parts := strings.Split(rule, "=") key := parts[0] var value string if len(parts) > 1 { value = parts[1] } switch key { case "required": if err := isRequired(valueField); err != nil { return err } case "min": if err := isMin(valueField, value); err != nil { return err } } }4. (可选)如果你对我如何处理 isRequired 和 isMin 验证规则感到好奇,请继续阅读。
func isMin(valueField reflect.Value, minStr string) error { typeField := valueField.Type() if minStr == "" { return nil } min, err := strconv.ParseFloat(minStr, 64) if err != nil { return fmt.Errorf("min value %f is not a number", min) } switch valueField.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if float64(valueField.Int()) < min { return fmt.Errorf("field %s must be greater or equal %d", typeField.Name(), int(min)) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if float64(valueField.Uint()) < min { return fmt.Errorf("field %s must be greater or equal than %d", typeField.Name(), uint(min)) } case reflect.Float32, reflect.Float64: if valueField.Float() < min { return fmt.Errorf("field %s must be greater or equal than %f", typeField.Name(), min) } } return nil }• isRequired 验证:
func isRequired(v reflect.Value) error { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: if v.Len() != 0 { return nil } case reflect.Bool: if v.Bool() { return nil } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if v.Int() != 0 { return nil } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if v.Uint() != 0 { return nil } } return fmt.Errorf("field %s is required", v.Type().Name()) }三. 使用包
一个很好的例子就是“validator”包,它具有一系列内置函数,如 required 和 min,可以在验证过程中使用,正如我们在上面的示例中所看到的。