http://127.0.0.1:8080/users
{
"Code": 200,
"Message": "OK",
"Success": true,
"Data": {
"Mobile": {
"Value": ""
},
"Age": {
"Value": 0
},
"Level": {
"Value": 0
},
"Nickname": {
"Value": ""
}
}
}
当我们请求用户列表接口时,参数都不传,Mobile、Age、Nickname字段为空我们知道查询数据库的时候不需要使用,因为默认零值在这三个字段的场景下时非法的,但是Level字段的零值是合法的,那么我们是使用还是不使用呢?
这就是臭名昭著的零值问题。
零值问题在增量更新中也广泛存在,例如更新用户昵称:
{
"Nickname": "John"
}
type User struct {
ID int
Mobile string
Age int
Nickname string
Level int
}
user {Nickname: John}
我们直接使用user去更新数据库,会导致除Nickname字段其他所有的字段都会更新为空。
两种方案解决零值问题:
1、使用指针
缺点:无处不在的nil判断,操作起来会非常繁琐
2、客户端指定更新字段 JSON Merge Patch && JSON Patch
缺点:客户端和服务器端同时增加开发成本
有没有更好的解决方案呢?
type Nickname struct {
Value string `binding:"min=2,max=10"`
Set bool
}
func (o *Nickname) SetTo(v string) {
o.Set = true
o.Value = v
}
func (o *Nickname) UnmarshalJSON(data []byte) error {
if data[0] != '{' {
o.SetTo(gjson.ParseBytes(data).String())
return nil
}
result := gjson.GetBytes(data, "Value")
if result.Exists() {
o.SetTo(result.String())
}
return nil
}
不管是使用指针还是指定更新字段,目的都是为了标识某一个字段是否是有效数据。
我们可以在属性对象中增加Set
变量,用来标识字段是否有效,然后在UnmarshalJSON
函数中解析数据的同时设置Set
变量,就这是Set模式。
Set模式优势:
1、杜绝了指针方案的各种繁琐操作,同时避免了nil异常
2、客户端无痕对接,降低了对接成本
那么后续又该如何使用Set模式呢,请看下文分解。