You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go Validator中实现多字段仅允许其一且非空验证?

解决方案

针对你的需求(两个字段必须且只能有一个有值),Go Validator可以通过两种方式实现:

方案一:结合内置标签组合

利用required_without和excluded_with两个内置标签组合,同时实现「必填其一」和「互斥」的要求:

type CoolName struct {
    Foo string `json:"foo" validate:"required_without=Bar excluded_with=Bar"`
    Bar string `json:"bar" validate:"required_without=Foo excluded_with=Foo"`
}

标签说明:

  • required_without=Bar:当Bar为空时,Foo必须非空
  • excluded_with=Bar:当Bar非空时,Foo必须为空
    两个字段的标签对称设置,就能严格保证「二选一且仅选一个」的规则。

方案二:自定义结构体验证函数

如果觉得标签组合不够直观,可以编写自定义的结构体级验证函数,直接实现逻辑判断:

1. 定义验证函数

func validateExclusiveOneOf(fl validator.FieldLevel) bool {
    // 获取结构体实例
    structObj := fl.Parent().Interface().(CoolName)
    // 统计非空字段数量
    nonEmptyCount := 0
    if structObj.Foo != "" {
        nonEmptyCount++
    }
    if structObj.Bar != "" {
        nonEmptyCount++
    }
    // 返回是否符合「仅一个非空」的规则
    return nonEmptyCount == 1
}

2. 注册验证函数

在初始化Validator时,将自定义函数绑定到CoolName结构体:

var validate *validator.Validate

func init() {
    validate = validator.New()
    // 注册结构体验证规则
    err := validate.RegisterStructValidation(validateExclusiveOneOf, CoolName{})
    if err != nil {
        panic(err)
    }
}

3. 使用验证

验证时直接调用validate.Struct()即可:

func main() {
    // 测试用例1:仅Foo有值 → 验证通过
    validCase := CoolName{Foo: "test"}
    if err := validate.Struct(validCase); err != nil {
        fmt.Println("验证失败:", err)
    } else {
        fmt.Println("验证通过")
    }

    // 测试用例2:Foo和Bar都有值 → 验证失败
    invalidCase := CoolName{Foo: "test", Bar: "test"}
    if err := validate.Struct(invalidCase); err != nil {
        fmt.Println("验证失败:", err)
    } else {
        fmt.Println("验证通过")
    }
}

两种方案对比:

  • 标签组合方案更简洁,无需额外代码,适合简单场景
  • 自定义函数方案更灵活,可扩展到更复杂的多字段互斥规则

内容的提问来源于stack exchange,提问作者Mustafa Güneş

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 05:10:21