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

How to convert a data array to a record using idiomatic F#

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

是否有比

更惯用的方法将数组转换为记录
let data = [0;1]
type Rec = {
    A : int
    B : int
}

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

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

几点评论:

您的记录类型定义是伪造的 - 那里不应该有 =。我假设你想要

type Rec = {
    A : int
    B : int
}

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

但我想知道记录是否适合放在这里。如果您的目标是拥有一个接受字节数组的函数,并且 returns 支持对该数据的各种强类型解释,那么可区分的联合可能是最好的。

也许是这样的:

// 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 |]