我相信我知道范围,但我不知道何时何地使用它们,或者如何使用它们。我没有“获得”范围。考虑这个例子:
假设我们有一个网络处理程序,我们无法控制,只要有一些新数据,就会在某个线程中调用我们的回调函数:
void receivedData(ubyte[] data)
此数据流包含具有布局
的数据包{
ushort size;
ubyte[size] body;
}
但是,网络处理程序不知道这一点,因此对dataReceived()
的调用可能包含一个或两个部分数据包,一个或多个完整数据包或组合。为简单起见,我们假设没有损坏的数据包,并且在连接关闭时我们会收到data.length == 0
。
我们现在想要的是一些漂亮的D代码,将所有这些混乱转变为对
的适当调用void receivedPacket(ubyte[] body)
我当然可以想到“蛮力”的方法来实现这一目标。但也许这里可能出现了我的困惑:范围可以发挥作用吗?我们可以将receivedData()
包装成一个很好的范围吗?怎么样?或者这不是你使用范围的问题吗?为什么不呢?
(如果使用范围更有意义,请随意重新定义该示例。)
答案 0 :(得分:2)
我要做的是
ubyte[1024] buffer=void;//temp buffer set the size as needed...
ushort filledPart;//length of the part of the buffer containing partial packet
union{ushort nextPacketLength=0;ubyte[2] packetLengtharr;}//length of the next packet
void receivedData(ubyte[] data){
if(!data.length)return;
if(nextPacketLength){
dataPart = min(nextPacketLength-filledPart.length,data.length);
buffer[filledPart..nextPacketLength] = data[0..dataPart];
filledPart += dataPart;
if(filledPart == nextPacketLength){
receivedPacket(buffer[0..nextPacketLength]);//the call
filledPart=nextPacketLength=0;//reset state
receivedData(datadataPart..$]);//recurse
}
} else{
packetLengtharr[]=data[0..2];//read length of next packet
if(nextPacketLength<data.length){//full paket in data -> avoid unnecessary copies
receivedPacket(data[2..2+nextPacketLength]);
receivedData(data[2+nextPacketLength..$]);//recurse
}else
receivedData(data[2..$]);//recurse to use the copy code above
}
}
它有三种可能的路径递归:
data
为空 - &gt;没有行动
nextPacketLength
设置为值!= 0 - &gt;将尽可能多的数据复制到缓冲区中,如果数据包已完成,请调用回调并重置filledPart
和nextPacketLength
,然后使用其余data
nextPacketLength == 0读取数据包长度(此处带有联合),如果完整数据包可用,则调用回调,然后使用其余数据进行递归
当数据只保留长度的第一个字节时,仍然只有一个错误,但我会让你弄明白(我现在懒得做)