Golang:如何用validator/v10的required_if验证依赖外层结构体的字段?
基于外层结构体字段实现嵌套结构体的条件验证(Go validator v10)
可以实现这种跨结构体的条件验证,核心是借助validator的自定义验证器功能,以下是具体操作步骤:
1. 编写自定义验证函数
需要编写一个自定义验证函数,它能获取外层Medicare结构体的CardType字段值,再判断当前CardExpiry.Day是否需要必填。
注意:验证函数中需要通过validator.FieldLevel的Parent()方法获取外层结构体实例,再提取CardType的值。
func requiredIfCardType(fl validator.FieldLevel) bool { // 获取外层Medicare结构体实例 medicare, ok := fl.Parent().Interface().(Medicare) if !ok { return false // 类型断言失败时直接返回验证不通过 } // 定义需要触发必填的CardType值 requiredTypes := map[string]bool{ "RECIPROCAL": true, "INTERIM": true, } // 如果CardType属于目标类型,检查Day字段是否不为空 if requiredTypes[medicare.CardType] { // 这里假设Day是int类型,根据实际类型调整判断逻辑 return fl.Field().Int() != 0 } // 非目标类型时,验证自动通过 return true }
2. 注册自定义验证器
在使用验证器前,需要把自定义函数注册到validator实例中:
import "github.com/go-playground/validator/v10" var validate *validator.Validate func init() { validate = validator.New() // 注册自定义验证器,指定标签名(比如required_if_cardtype) err := validate.RegisterValidation("required_if_cardtype", requiredIfCardType) if err != nil { panic(err) } }
3. 给结构体字段添加自定义标签
在CardExpiry.Day字段上添加自定义验证标签,关联刚才注册的验证器:
type CardExpiry struct { Day int `json:"day" validate:"required_if_cardtype"` Month int `json:"month"` Year int `json:"year"` } type Medicare struct { CardType string `json:"card_type" validate:"required,oneof=RECIPROCAL INTERIM OTHER"` CardExpiry CardExpiry `json:"card_expiry" validate:"required"` }
4. 执行验证逻辑
正常解析JSON到结构体后,调用验证器的Struct()方法即可完成验证:
func main() { // 示例JSON载荷 jsonData := []byte(`{"card_type":"RECIPROCAL","card_expiry":{"month":12,"year":2025}}`) var medicare Medicare err := json.Unmarshal(jsonData, &medicare) if err != nil { panic(err) } // 执行验证 err = validate.Struct(medicare) if err != nil { // 处理验证错误 for _, e := range err.(validator.ValidationErrors) { println("验证失败:", e.Field(), e.Tag()) } } }
补充说明
- 如果
Day是其他类型(比如string),需要调整自定义函数中的判断逻辑(比如fl.Field().String() != "")。 - 若外层结构体是指针类型,需要先解引用再做类型断言:
medicare, ok := fl.Parent().Interface().(*Medicare)。
内容的提问来源于stack exchange,提问作者samme4life
相关产品推荐
相关产品推荐

