F#匹配数组的开头

时间:2014-11-17 13:43:19

标签: arrays f# pattern-matching f#-3.0

我有一个Byte[]缓冲区,可能包含一个或多个数据帧,我需要读取第一个字节以了解实际帧的长度。

这是一个非工作的"我想做的版本:

let extractFrame (buffer:byte[]) =
  match buffer with 
    | [|head1;head2;head3;..|] when head2 < (byte)128 -> processDataFrame buffer head2
    | <...others....>
    | _ -> raise(new System.Exception())

基本上,我需要评估前三个字节,然后使用缓冲区和帧的实际长度调用processDataFrame。根据标题,框架可以是数据,控制等......

这可以通过任何匹配(列表,序列等等)来完成吗?或者我是否必须创建另一个只有标题长度的小数组?(我想避免这种情况)。

2 个答案:

答案 0 :(得分:3)

如果您想使用匹配,可以创建活动模式(http://msdn.microsoft.com/en-us/library/dd233248.aspx):

let (|Head1|_|) (buffer:byte[]) =
    if(buffer.[0] (* add condition here *)) then Some buffer.[0]
    else None 

let (|Head2|_|) (buffer:byte[]) =
    if(buffer.[1] < (byte)128) then Some buffer.[1]
    else None 

let extractFrame (buffer:byte[]) =
  match buffer with 
    | Head1 h1 -> processDataFrame buffer h1
    | Head2 h2 -> processDataFrame buffer h2
........
    | _ -> raise(new System.Exception())

答案 1 :(得分:3)

我认为使用普通if构造实际上这可能更容易。

但正如Petr提到的,您可以使用活动模式并定义自己的模式,从阵列中提取特定信息。为了模拟你正在做的事情,我实际上会使用一个参数化的活动模式 - 你可以从你需要的数组中给它一些元素的数量,它会给你一个数组,例如: 3个元素:

let (|TakeSlice|_|) count (array:_[]) = 
  if array.Length < count then None
  else Some(array.[0 .. count-1])

let extractFrame (buffer:byte[]) =
  match buffer with 
  | TakeSlice 3 [|head1;head2;head3|] when head2 < (byte)128 -> 
      processDataFrame buffer head2
  | <...others....>
  | _ -> raise(new System.Exception())  

此方法的一个缺点是您的模式[|h1; h2; h3|]必须与您指定的长度匹配3 - 编译器无法为您检查此内容。