简体   繁体   English

F#匹配数组的开头

[英]F# match the beginning of an array

I have a Byte[] buffer that may contain one or multiple data frames, I need to read the first bytes to know how long the actual frame is. 我有一个Byte[]缓冲区,其中可能包含一个或多个数据帧,我需要读取第一个字节才能知道实际帧的长度。

This is a "non-working" version of what I want to do: 这是我要执行的“无效”版本:

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

Basically, I need to evaluate the first three bytes, and then call processDataFrame with the buffer and the actual length of the frame. 基本上,我需要评估前三个字节,然后使用缓冲区和帧的实际长度调用processDataFrame Depending on the headers, the frame can be data, control, etc... 根据标题,帧可以是数据,控件等。

Can this be done with any kind of match (lists, sequences, ...etc...)? 可以使用任何类型的匹配项(列表,序列等)来完成吗? Or will I have to create another small array with just the length of the header?(I would like to avoid this). 还是我必须创建仅具有标题长度的另一个小数组?(我想避免这种情况)。

If you want to use matching you could create active pattern ( http://msdn.microsoft.com/en-us/library/dd233248.aspx ): 如果要使用匹配,则可以创建活动模式( http://msdn.microsoft.com/zh-cn/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())

I think that this might actually be easier to do using the plain if construct. 我认为使用简单的if构造实际上可能更容易。

But as Petr mentioned, you can use active patterns and define your own patterns that extract specific information from the array. 但是正如Petr所述,您可以使用活动模式并定义自己的模式,以从阵列中提取特定信息。 To model what you're doing, I would actually use a parameterized active pattern - you can give it the number of elements from the array that you need and it gives you an array with eg 3 elements back: 为了对您正在做的事情建模,我实际上会使用一个参数化的活动模式-您可以为它提供所需数组中元素的数量,并为您提供一个包含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())  

One disadvantage of this approach is that your pattern [|h1; h2; h3|] 这种方法的一个缺点是您的模式[|h1; h2; h3|] [|h1; h2; h3|] [|h1; h2; h3|] has to match to the length that you specified 3 - the compiler cannot check this for you. [|h1; h2; h3|]必须匹配您指定的长度3编译器无法为您检查此长度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM