我在项目中有这样的代码,我意识到它不是 以功能性方式编写:
let data = Array.zeroCreate(3 + (int)firmwareVersions.Count * 27)
data.[0] <- 0x09uy //drcode
data.[1..2] <- firmwareVersionBytes //Number of firmware versions
let mutable index = 0
let loops = firmwareVersions.Count - 1
for i = 0 to loops do
let nameBytes = ASCIIEncoding.ASCII.GetBytes(firmwareVersions.[i].Name)
let timestampBytes = this.getTimeStampBytes firmwareVersions.[i].Timestamp
let sizeBytes = BitConverter.GetBytes(firmwareVersions.[i].Size) |> Array.rev
data.[index + 3 .. index + 10] <- nameBytes
data.[index + 11 .. index + 24] <- timestampBytes
data.[index + 25 .. index + 28] <- sizeBytes
data.[index + 29] <- firmwareVersions.[i].Status
index <- index + 27
firmwareVersions是一个列表,它是csharp库的一部分。 它(并且不应该)有任何关于如何转换成它的知识 一个字节数组。我意识到上面的代码非常缺乏功能,所以我试过了 像这样改变它:
let headerData = Array.zeroCreate(3)
headerData.[0] <- 0x09uy
headerData.[1..2] <- firmwareVersionBytes
let getFirmwareVersionBytes (firmware : FirmwareVersion) =
let nameBytes = ASCIIEncoding.ASCII.GetBytes(firmware.Name)
let timestampBytes = this.getTimeStampBytes firmware.Timestamp
let sizeBytes = BitConverter.GetBytes(firmware.Size) |> Array.rev
Array.concat [nameBytes; timestampBytes; sizeBytes]
let data =
firmwareVersions.ToArray()
|> Array.map (fun f -> getFirmwareVersionBytes f)
|> Array.reduce (fun acc b -> Array.concat [acc; b])
let fullData = Array.concat [headerData;data]
所以现在我想知道这是否是更好(更实用)的方式 写代码。如果是这样的话......为什么我要做什么改进, 如果没有,为什么不呢?我该怎么做呢?
建议,反馈,评论?
谢谢
更新
只想添加更多信息。 这是处理二进制通信数据的某个库的一部分 协议。我看到代码的第一个版本的唯一好处是 人们用不同的语言实现协议(情况就是如此) 在我们的情况下)可能会更好地了解每个字节数 part占用了它们在字节流中的确切位置......只是一个注释。 (因为不是每个人都懂英语,但我们所有的合作伙伴都可以阅读代码)
答案 0 :(得分:2)
我倾向于内联所有内容,因为整个程序变得如此短暂:
let fullData =
[|yield! [0x09uy; firmwareVersionBytes; firmwareVersionBytes]
for firmware in firmwareVersions do
yield! ASCIIEncoding.ASCII.GetBytes(firmware.Name)
yield! this.getTimeStampBytes firmware.Timestamp
yield! BitConverter.GetBytes(firmware.Size) |> Array.rev|]
如果你想传达字节的位置,我会把它们放在每行末尾的注释中。
答案 1 :(得分:1)
代码运行的频率是多少?
'数组连接'的优点是它确实更容易“看到”逻辑部分。缺点是它会产生大量垃圾(分配临时数组),如果在紧密循环中使用它也可能会更慢。
另外,我想也许你的“Array.reduce(...)”可能只是“Array.concat”。
总的来说,我更喜欢第一种方式(只创建一个巨大的数组),尽管我会以不同的方式使逻辑更明显(例如,有一个命名常量HEADER_SIZE等)。
虽然我们正在努力,但我可能会添加一些断言以确保例如nameBytes具有预期的长度。
答案 2 :(得分:1)
我更喜欢您的第一个版本,因为索引可以更好地了解偏移量,这是问题的一个重要部分(我假设)。命令式代码突出显示字节偏移,如果您的合作伙伴不能/不读取文档,这可能很重要。功能代码强调将结构粘在一起,如果字节偏移量不够重要,也可以在文档中提及。
索引通常是意外的复杂性,在这种情况下应该避免。例如,您的第一个版本的循环可能是for firmwareVersion in firmwareVersion
而不是for i = 0 to loops
。
此外,就像布莱恩所说的那样,使用常数来抵消偏移会使命令式版本更具可读性。