Go如何实现支持不同结构体入参的通用参数校验函数
Go通用结构体参数校验实现方案
方案1:基于反射适配你现有调用逻辑
动态读取结构体字段的需求可以直接用Go标准库的reflect包实现,不需要枚举所有结构体类型,代码实现如下:
import ( "fmt" "reflect" ) func CheckParams(input interface{}, paramsWithType map[string]string) error { // 获取输入参数的反射值 val := reflect.ValueOf(input) // 校验传入参数是否为结构体类型 if val.Kind() != reflect.Struct { return fmt.Errorf("input must be a struct") } // 遍历校验规则 for fieldName, expectType := range paramsWithType { // 按字段名获取结构体字段值 fieldVal := val.FieldByName(fieldName) // 字段不存在直接返回错误 if !fieldVal.IsValid() { return fmt.Errorf("field %s not exist", fieldName) } // 校验字段类型是否符合预期 actualType := fieldVal.Kind().String() if actualType != expectType { return fmt.Errorf("field %s type mismatch, expect %s, actual %s", fieldName, expectType, actualType) } // 校验非零值,可根据需求扩展其他校验规则 if fieldVal.IsZero() { return fmt.Errorf("field %s can not be zero value", fieldName) } } return nil }
你原有调用逻辑不需要修改,直接复用即可:
func main(){ var input Interface1Input input.Age = 20 input.Address = "北京市海淀区" paramsMap := map[string]string{ "age": "int", "address": "string", } if err := CheckParams(input, paramsMap); err != nil { fmt.Println("校验失败:", err) return } fmt.Println("校验通过") }
方案2:结构体Tag实现(业务场景推荐)
如果不需要每次调用灵活指定校验字段,更推荐用结构体Tag绑定校验规则,复用性和可维护性更高,示例如下:
定义结构体时添加校验Tag:
type Interface1Input struct { Name string `validate:"required"` Age int `validate:"required,min=1"` Address string `validate:"required"` } type Interface2Input struct { Name string `validate:"required"` Phone string `validate:"required,len=11"` Gender string `validate:"required,oneof=男 女"` }
校验函数读取Tag规则完成校验,不需要额外传入规则map:
func ValidateStruct(input interface{}) error { val := reflect.ValueOf(input) if val.Kind() != reflect.Struct { return fmt.Errorf("input must be a struct") } typ := val.Type() for i := 0; i < val.NumField(); i++ { field := typ.Field(i) tag := field.Tag.Get("validate") // 没有配置校验规则的字段直接跳过 if tag == "" || tag == "-" { continue } fieldVal := val.Field(i) // 可根据tag值解析扩展更多规则,比如min、max、长度校验等 if tag == "required" && fieldVal.IsZero() { return fmt.Errorf("field %s is required", field.Name) } } return nil }
内容的提问来源于stack exchange,提问作者pkzz
相关产品推荐
相关产品推荐

