前言
关于默认值的问题,先用以下简单的 java 代码示例说明一下:
public class Variable {
private int intNum;
public int getIntNum() {
return intNum;
}
public void setIntNum(int intNum) {
this.intNum = intNum;
}
}
public class MainServer {
public static void main(String[] args) {
Variable var = new Variable();
System.out.println("没set时,intNum默认值为:" + var.getIntNum());
var.setIntNum(0);
System.out.println("set之后,intNum的值是:" + var.getIntNum());
}
}
输出:
没set时,intNum默认值为:0
set之后,intNum的值是:0
输出的都是 0,一个是默认值( java 中 int 类型不赋值的话默认为 0),一个是通过 setIntNum 方法给它赋值为 0
在上面的代码中你可以很容易的知道 var 中的 intNum 是默认值还是不是默认值。
那如果是微服务呢,A微服务通过网络把 var 对象传给 B 微服务,B 微服务从 var 中得到的 intNum 是 0,B 微服务是区分不出是不是默认值的。
举个例子:
如果客户输入一个值 ,A 微服务就调用 setIntNum 方法赋值给 intNum ,然后把 var 通过网络把 var 对象传给 B 微服务,B 微服务就把用户的输入存到数据库。
但是如果客户输入 0 这个时候 B 微服务是并不知道这个 0 是默认值还是调用 setIntNum 方法赋值的,所以 B 微服务就不知道要不要把这个 0 存入数据库。
Protobuf 里面也是和上面的例子一样的。
一 、protobuf 默认值说明
Protobuf 是目前非常主流的二进制序列化格式,GRPC 默认使用 Protobuf v3 格式。
proto里没有设置的参数是会有默认值的。
假设 proto 文件里如下:
message Account {
string name = 1
int profit_rate = 2
}
profit_rate 的默认值会是 0,所以就算前端 不传参数或者不给它复制也会有默认值 0,代码里无法区分它是默认值 0 还是赋值给的 0 。
二、 使用 oneof
为了避免上面的问题 proto 文件里可以使用 oneof :
message Account {
string name = 1;
oneof profit_rate {
int profitrate = 2;
}
}
这样,在 Java 中,可以用 XxxCase() == XxxCase.XXX_NOT_SET 或者 XxxCase().getNumber == 0 判断是否设置 oneof ,以此来判断是不是赋值的而不是默认值。
//如果设置了值则获取值 (即如果前端传了值才进入if,没传值用的默认值的话就不进if )
if (Account.CheckProfitrateCase.PROFITRATE == account.getCheckProfitrateCase()) {
int profitrate = account.getProfitrate();
}
其他类型的默认值如下:
对于字符串,默认值为空字符串。
对于字节,默认值为空字节。
对于布尔值,默认值为false。
对于数字类型,默认值为零。
对于枚举,默认值为第一个定义的枚举值,必须为0。
三、四种 grpc 模式示例
如果你对 grpc 感兴趣,可以看下我用 springboot 写的 grpc 示例,github地址:grpc-spring-boot-demo
里面分别介绍了四种 grpc 模式:简单 grpc、服务端流式 grpc、客户端流式 grpc、双向流式 grpc
参考文章:
区分 Protobuf 中缺失值和默认值
语言指南(proto3)
集成grpc,普通对象与grpc对象转换