一、概述

所谓可null、可空,其实是一个特性的两个方面,某些情况下,我们不需要传递某个字段的值,则可以将该字段“空”起来,不赋值,则接收方在收到该字段时会自动解析为null值。所以空是对于发送方而言,而null则是对于接收方而言,但FAST流中并不会因为没有对该字段赋值就可以节省下一个字节,而是需要传递一个特殊值来告知接收方这个字段未赋值,接收方应解析为null。不同的数据类型为适应可null(空)的特性有一些较奇怪的变换,下面看实例。

这里先回顾一下scalar这个类,可见是通过修改optional来设置字段是否可空。

 

FAST协议详解3 可null(空)类型_FAST

 

 

二、不同数据类型的可null(空)

数据类型

说明

INTEGER整数

可空整数,编码后数值+1。比如我要传递1,则实际传递的是2,解码方收到后自行减去1。原因是要用0值代表null。但传递负值时就不需要再自行减1了。

ASCII字符串

可空字符串,编码后数值不变。但需要区分null、空字符串、\0。

10000000->null

00000000 10000000->空字符串

00000000 00000000 10000000->\0

STRING字符串

同上

BYTEVECTOR字节向量

字节向量分为长度和数据两部分,其中长度部分若为10000000则表明字段为null,而10000001则表明字节向量长度为0,故而长度部分在解码后需要自行减去1。

DECIMAL浮点数

浮点数的传输也分为两部分,第一部分是小数点位数,第二部分是数值。 其中小数点位数部分若为10000000则表明字段为null,但正常传递浮点数时位数部分不需要再减去1,比如-2是“11111110”,只有传递1这样无小数点的数值时,由于其小数点位数为“10000000”,必须要再加1。所以小数点位数部分在负值时不需要自行减1,在正直时需要自行减1。

 

三、可null(空)实例

1、INTEGER整数

FAST协议详解3 可null(空)类型_字段_02

 

上述代码运行结果如下:

msg111= -> {123, 1, null, 3}

outByteStr=11000000,11111011,10000001,10000000,10000011,

可以看到第二个字段传输的值是10000000,在这里会解析为null

 

问题:如何传递非空值?

FAST协议详解3 可null(空)类型_浮点数_03

 

上述代码运行结果如下:

msg111= -> {123, 1, 2, 3}

outByteStr=11000000,11111011,10000001,10000011,10000011,

可以看到,第二个字段值是2,但传输的是10000011(0000011->3),对于可空字段,解码时需要自行减去1,因为null把10000000占了,传递0需要使用1000001。

 

问题:如何传递负值?

FAST协议详解3 可null(空)类型_浮点数_04

 

上述代码运行结果如下:

msg111= -> {123, 1, -2, 3}

outByteStr=11000000,11111011,10000001,11111110,10000011,

可以看到,对于负值是直接传递的,不需要加一或者减一。

 

2、ASCII字符串

FAST协议详解3 可null(空)类型_浮点数_05

 

上述代码运行结果如下:

msg111= -> {123, 1, 123, 3}

outByteStr=11000000,11111011,10000001,00110001,00110010,10110011,10000011,

可见对于字符串,数值转换并未有改变。

 

问题:如何传输null

做如下修改:

Message message = new Message(template);
message.setInteger(1, 1);
//message.setString(2, "123");
message.setInteger(3, 3);

运行结果如下:

msg111= -> {123, 1, null, 3}

outByteStr=11000000,11111011,10000001,10000000,10000011,

可见,是通过10000000来传输null值

 

问题:如何传输空字符串

做如下修改:

Message message = new Message(template);
message.setInteger(1, 1);
message.setString(2, "");
message.setInteger(3, 3);

运行结果如下:

msg111= -> {123, 1, , 3}

outByteStr=11000000,11111011,10000001,00000000,10000000,10000011,

可见是通过00000000,10000000来传输空字符串。

 

问题:如何传输\0字符

做如下修改:

Message message = new Message(template);
message.setInteger(1, 1);
message.setString(2, "\0");
message.setInteger(3, 3);

运行结果如下:

msg111= -> {123, 1,  , 3}

outByteStr=11000000,11111011,10000001,00000000,00000000,10000000,10000011,

可见是通过00000000,00000000,10000000来传输\0字符

 

3、STRING字符串

同ASCII字符串

 

4、BYTEVECTOR字节向量

FAST协议详解3 可null(空)类型_浮点数_06

 

上述代码运行结果如下:

msg111= -> {123, 1, 123, 3}

outByteStr=11000000,11111011,10000001,10000100,00110001,00110010,00110011,10000011,

注意这里00000100的值是4,而123字符串的实际长度是3,所以这里需要减去1。

 

问题:如何传递null

做如下修改:

Message message = new Message(template);
message.setInteger(1, 1);
//message.setByteVector(2, "123".getBytes("GBK"));
message.setInteger(3, 3);

运行结果如下:

msg111= -> {123, 1, null, 3}

outByteStr=11000000,11111011,10000001,10000000,10000011,

当字段不设值时,使用10000000来代表null。

 

5、DECIMAL浮点数

FAST协议详解3 可null(空)类型_FAST_07

 

上述代码运行结果如下:

msg111= -> {123, 1, 0.01, 3}

outByteStr=11000000,11111011,10000001,11111110,10000001,10000011,

可以看到,小数点位数值是-2,没有因为可null属性而需要加一或减一。

 

问题:如何传递null值

代码修改如下:

Message message = new Message(template);
message.setInteger(1, 1);
//message.setDecimal(2, 0.01);
message.setInteger(3, 3);

运行结果如下:

msg111= -> {123, 1, null, 3}

outByteStr=11000000,11111011,10000001,10000000,10000011,

与BYTEVECTOR类似,小数点位数这里传递10000000即代表null,对于无可null属性的浮点数,10000000则表示无小数点。

 

问题:无小数点如何表现

代码修改如下:

Message message = new Message(template);
message.setInteger(1, 1);
message.setDecimal(2, 2);
message.setInteger(3, 3);

运行结果如下:

msg111= -> {123, 1, 2, 3}

outByteStr=11000000,11111011,10000001,10000001,10000010,10000011,

可以看到,小数点位数这里值是正数1,因为10000000已经用于表示null了,所以正数都要减去1,实际表明的是无小数点。

 

四、回顾

总的看来,其实空也是一个需要传递的值,而为了区分空(null)与0,对于正数将全部数值都+1,对于负数则无影响。对于字节向量和浮点数则是在字节向量的长度和小数点位数这里进行区分,字符串则无影响,但需要注意区分null、空字符串、\0字符。