Gin - dive 标签用法笔记

介绍

dive 是 Gin 依赖的 go-playground/validator 库中专门用于切片(slice)/数组的校验标签,作用是「穿透切片外层,对切片内的每个元素执行后续校验规则」。

一、核心场景:切片必传 + 元素规则校验

场景 1:仅要求「切片必传 + 每个元素长度 ≥1」

需求拆解:

  • 必传 tags 字段(不允许 JSON 中缺失该字段,即切片不能为 nil
  • 切片内每个 tag 的字符串长度 ≥1(不允许空字符串元素)

实现代码:

1
2
3
4
5
6
type TagsInput struct {
// required:校验切片必传(JSON 中必须包含 tags 字段,切片不能为 nil)
// dive:穿透到切片内部,对每个元素执行后续规则
// min=1:对每个元素校验,字符串长度 ≥1(元素级规则)
Tags []string `json:"tags" binding:"required,dive,min=1"`
}

满足条件

1
2
3
{"tags": ["go", "gin", "validator"]}  // 切片存在,元素均非空
{"tags": ["a"]} // 切片存在,单个非空元素
{"tags": []} // 切片为空但存在(不违反 required,元素无违规,会通过)

错误请求

1
2
{}  // 缺失 tags 字段(违反 required)
{"tags": ["", "gin"]} // 存在空字符串元素(违反 dive 后的 min=1)

场景 2:要求「切片必传 + 切片长度 ≥1 + 每个元素长度 ≥1」

需求拆解:

  • 比场景 1 多了「切片非空」要求
  • 必传 tags 字段(切片不能为 nil
  • 切片本身至少有 1 个元素(长度 ≥1)
  • 每个 tag 的字符串长度 ≥1(元素非空)

实现代码

注意:两次 min=1 作用不同:

1
2
3
4
5
type TagsInput struct {
// 第 1 个 min=1:切片级规则,要求切片长度 ≥1(配合 required 确保切片非空)
// 第 2 个 min=1:元素级规则,要求每个元素长度 ≥1(需在 dive 后)
Tags []string `json:"tags" binding:"required,min=1,dive,min=1"`
}

合法请求

1
2
{"tags": ["go", "gin"]}  // 切片非空,元素均非空
{"tags": ["a"]} // 切片长度=1,元素非空

错误请求

1
2
3
{}  // 缺失 tags 字段(违反 required)
{"tags": []} // 切片为空(违反切片级 min=1)
{"tags": ["", "gin"]} // 存在空元素(违反元素级 min=1)

二、关键知识点拆解

1. 两次 min=1 的区别(核心重点)

位置 作用层级 含义 示例(违反规则的情况)
required 后、dive 切片级 要求切片的长度 ≥ N(此处 N=1) {"tags": []}(切片长度=0)
dive 元素级 要求切片中每个元素满足 min=N(字符串长度 ≥N、数字 ≥N 等) {"tags": [""]}(元素长度=0)

注意:min多类型兼容规则,对切片作用于长度,对字符串作用于字符数,对数字作用于数值大小

2. dive 标签的核心作用

  • 没有 dive 时,所有校验规则仅作用于切片本身(如是否存在、长度等),不关心元素;
  • 加上 dive 后,后续的所有规则都会穿透到切片内部,逐个应用于每个元素;
  • 若切片是嵌套结构体切片(如 []User),dive 后会自动校验结构体的字段规则(无需额外配置)。

示例(嵌套结构体切片):

1
2
3
4
5
6
7
8
9
type User struct {
Name string `json:"name" binding:"required"` // 结构体字段必传
Age int `json:"age" binding:"gt=18"` // 年龄>18
}

type UserListInput struct {
// 切片必传 + 切片长度≥1 + 每个 User 结构体字段满足规则
Users []User `json:"users" binding:"required,min=1,dive"`
}

3. 常见误区

  • 认为 required 能限制切片非空
    说明:required 仅校验 切片字段存在(非 nil),空切片 [] 会通过 required 校验(需配合 min=1 限制切片长度)。

  • 省略 dive 直接写元素规则
    说明:binding:"required,min=1" 仅作用于切片长度,不会校验元素;必须加 dive 才能让规则作用于元素。

  • 重复 dive 或顺序错误
    说明: dive 只需写一次,且必须在切片级规则之后、元素级规则之前(正确顺序:required → 切片规则 → dive → 元素规则)。

三、扩展场景(灵活组合规则)

场景:切片必传 + 元素是邮箱格式

1
2
3
4
type EmailListInput struct {
// 切片必传 + 至少 2 个元素 + 每个元素是合法邮箱
Emails []string `json:"emails" binding:"required,min=2,dive,email"`
}

合法请求:

1
{"emails": ["test1@example.com", "test2@example.com"]}

错误请求:

1
2
{"emails": ["test1@example.com"]}  // 切片长度=1(违反 min=2)
{"emails": ["test1.example.com", "test2@example.com"]} // 第一个元素非邮箱格式

总结

业务需求 binding 规则
切片必传,元素无要求(允许空切片、空元素) required
切片必传,元素非空(允许空切片) required,dive,min=1
切片必传 + 切片非空 + 元素非空 required,min=1,dive,min=1
切片必传 + 切片长度≥N + 元素满足特定格式 required,min=N,dive,元素规则(如 dive,email

Gin - dive 标签用法笔记
https://blog.pangcy.cn/2025/11/23/后端编程相关/go/gin/Gin - dive 标签用法笔记/
作者
子洋
发布于
2025年11月23日
许可协议