如何使用惯用的F#将数据数组转换为记录

时间:2015-03-11 15:01:28

标签: f#

我正在尝试创建一个与硬件交互的通信库。该协议由具有标头(源/目标地址,命令编号,长度)和命令特定有效负载的字节数组组成。我正在为每个命令创建记录类型,以使它们更加用户友好。

是否存在将数组转换为记录而不是

的惯用方法
let data = [0;1]
type Rec = {
    A : int
    B : int
}

let convert d =
  {
    A = d.[0]
    B = d.[1]
  }

当记录大得多时,这可能变得非常乏味。

1 个答案:

答案 0 :(得分:2)

一些评论:

你记录的类型定义是假的 - 那里应该没有=。我想你想要

type Rec = {
    A : int
    B : int
}

您提到了字节数组,但您的data值是一个List。按索引访问列表项是昂贵的(O(n)),应该避免。如果您打算将其声明为数组,则语法为let data = [|0;1|]

但我想知道唱片是否适合这里。如果您的目标是拥有一个接受字节数组的单个函数并返回该数据的各种强类型解释,那么区分联合可能是最好的。

也许是这些方面的东西:

// various possible command types
type Commands =
    | Command1 of byte * int    // maybe payload of Command1 is known to be an int
    | Command2 of byte * string // maybe payload of Command1 is known to be a string

// active pattern for initial data decomposition
let (|Command|) (bytes : byte[]) =
    (bytes.[0], bytes.[1], Array.skip 2 bytes)

let convert (bytes : byte[]) =
    match bytes with
    | Command(addr, 1uy, [| intData |]) ->
        Command1(addr, int intData)
    | Command(addr, 2uy, strData) ->
        Command2(addr, String(Text.Encoding.ASCII.GetChars(strData)))
    | _ ->
        failwith "unknown command type"

// returns Command1(0x10, 42)
convert [| 0x10uy; 0x01uy; 0x2Auy |]

// returns Command2(0x10, "foobar") 
convert [| 0x10uy; 0x02uy; 0x66uy; 0x6Fuy; 0x6Fuy; 0x62uy; 0x61uy; 0x72uy |]