【问题标题】:F# match the beginning of an arrayF# 匹配数组的开头
【发布时间】:2014-11-17 13:43:18
【问题描述】:

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

这是我想做的“非工作”版本:

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

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

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

【问题讨论】:

  • 用 if/then 评估前三个字节不是更容易吗?
  • 这就是我想要找出的......有很多情况,我想知道在 F# 中这样做的正确方法

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


【解决方案1】:

如果您想使用匹配,您可以创建活动模式 (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())

【讨论】:

  • 对,这更有意义。谢谢!
【解决方案2】:

我认为使用普通的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 - 编译器无法为您检查。

【讨论】:

  • 我不能每次都创建一个新数组,因为它是一个服务器应用程序,每秒会创建数千个。
  • 我猜你可以想出更聪明的方法——比如 return ArraySegment :-)
  • 对,每秒仍然有数千个这样的对象:D 使用缓冲区、偏移和长度让我感觉更轻松......也许太老了。
猜你喜欢
  • 2011-04-12
  • 1970-01-01
  • 2015-07-12
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多