gin框架-bindingrequired无法接收零值的问题">一:问题场景
在Go中,当使用encoding/json包解码JSON数据到结构体时:
- 如果前端未传递某个字段,validator会将该字段设置为其类型的零值。
- 如果前端传递了该字段,并且是零值,validator同样会将其设置为相应的零值。
这意味着,仅凭字段的值,无法区分字段是未传递还是传递了零值。这在某些场景下可能导致问题。
二:解决方法
使用指针与required
标签,可以解决上面的问题。
(1)指针
将字段设置为指针类型,那么:
- 如果前端未传递该字段,validator会将指针设置为
nil
。 - 如果前端有传递该字段,validator会将指针指向相应的值。
这意味着,使用指针,可以区分参数传递了或未传递。
(2)required
标签
required
会验证字段值是否为零值,如果为零值,则验证不通过。
(3)结合使用
对于接口中定义的字段参数,按照是否必传、是否可为零值,可分4种情况:
-
必传,不可以为零值
参数是必传的,并且不能是零值(比如购买数量)
required
-
必传,可为零值
这种情况,参数是必传的,如果传的是零也要判断出来(比如传状态0或1)
required
+ 指针 -
非必传,不可以为零值
这种情况,前端可以不传,但是传的参数不能是【零】(比如前端传筛选条件,要么不筛选,要么提供一个有效的值)
非零条件
-
非必传,可为零值
这种情况,前端可以不传,但是传了【零】,我要能判断出来(比如把数量改为0,把描述文字改为空)
指针
三:总结
如果前端传的【零】有效,就使用指针。
必选参数,加required
,没什么好说的。
四:示例
gin框架-bindingrequired无法接收零值的问题">解决go gin框架 binding:"required"`无法接收零值的问题
(1)未传指针
在用于绑定的结构体中,通常会使用 validator
库进行参数的校验,比如:
type User struct {Name string `json:"name" binding:"required" example:"kkk"`Age int `json:"age" binding:"required" example:"18"`Status int `json:"status" binding:"required" example:"1"`}
我们规定前端传递的参数中,user、age、status 参数都为必填
然后在 Handler
函数中使用 ShouldBindJSON
绑定参数,如下:
func handlerT(c *gin.Context) {var user Userif err := c.ShouldBindJSON(&user); err != nil {fmt.Println(err)c.JSON(400, gin.H{"msg": "参数错误" + err.Error()})return}}
测试问题
当 status 值为 0 的时候,参数校验就会不通过
(2)传指针
原因是:Go 中会给结构体中没有赋值的字段赋予零值(int 类型默认 0、string 类型默认 "",等等),标签写成 require
时,如果传递零值,validator
校验的时候就会认为没有传递这个字段,进而报错
解决方法也很简单,既然原因是因为字段的类型零值是 0,那选用默认值不是 0 的数据类型,而且也要是数值类型
所以,解决方法就是:把 int
类型改为 *int
类型,使用 int 的指针类型,零值为 nil,这样传递的时候就能成功绑定
结构体改为:
type User struct {Name string `json:"name" binding:"required" example:"kkk"`Age int `json:"age" binding:"required" example:"18"`Status *int `json:"status" binding:"required" example:"1"`
}
测试
注意
可以看到,user.Status == 0
这一段报错了,因为 user.Status
是指针类型,不能直接与 int 类型比较,要想比较只能加上地址符 *
,或者再使用一个变量接收由 *int
类型转换来的 int
类型
(3)小结
当遇到 validator
库无法校验零值时,把数据类型换为对应的指针类型即可正常接收,但是在后续逻辑中,不能直接用这个指针类型的值进行常规运算,要么加上地址符 *
要么用中间变量接收转换后的值