我需要一个小实用程序函数,它从8个字节的数组生成校验和。
现在,这本身是微不足道的,除了我不能在C#中使用byte Checksum(byte[8] input)
作为方法声明 - 我不能指定数组的大小,所以我必须使用byte [],这可以是任何size,然后在方法体中,我需要检查输入是否为null,长度为== 8。
我只是想知道F#是否能做到这一点?我听说F#有更多选项来限制函数的可接受参数(例如,判别联盟)?
当然,在这个简单的例子中,F#会有点矫枉过正,但我很好奇。
答案 0 :(得分:4)
假设您不希望调用者单独传递它们,byte[]
arg是IMO罚款;我做的唯一改变就是我也考虑传入一个起始偏移量(因为我经常发现自己从byte[]
开始工作 - 但这取决于你的背景。)
如果你真的想避免这种丑陋,你可以考虑把它当作long
(或者可以说更好(因为负面的右移)来处理工作:ulong
)。你总是知道它的长度恰好是8个字节,并且它避免了一些启动查找。
您可以通过移动或通过byte*
和ulong*
的不安全演员来切换这两种格式
答案 1 :(得分:3)
我想说正确的方法是创建一个包含字节[8]的type
并将其用作参数。
话虽如此,我可以考虑使用活动模式,但看起来有点矫枉过正:
let (|Is8|NotIs8|) (input : byte[]) = if input.Length = 8 then Is8 else NotIs8
let testFunction (a : 'T[]) =
match a with
| Is8 -> printfn "yes it is 8 in size"
| NotIs8 -> printfn "it is not 8 in size"
答案 2 :(得分:2)
两种语言都不能指定函数采用特定长度的数组。这个问题是检查调用者是否实际提供具有该长度的数组是非常困难的。可以在new byte[8]
直接创建数组时检查它,但所有其他情况都需要一些棘手的技术。
部分由Code Contracts完成,{{3}}是一种可以安装到Visual Studio中并与C#和F#一起使用的附加检查工具。它允许你写一些类似的东西:
byte CheckSum(byte[] data) {
Contract.Requires(data != null);
Contract.Requires(data.Length == 8);
// Implementation
}
代码契约附带了一个工具,当您使用错误大小的数组调用CheckSum
时,它会在编译时向您发出警告。它还可以生成运行时检查(当它无法静态确定调用是否正确时)。
答案 3 :(得分:1)
在F#(或任何其他.NET语言)中,类型不能依赖于某个值,因此答案是否定的,您不能这样做。 (注意,可以在C ++模板中对其进行编码,因为模板可以依赖于整数参数。)使用byte []的包装类型只是将运行时长度检查转换为包装器对象的构造,并没有真正改善这种情况。
在编译时实际强制正确类型的唯一方法我可以想到使用8元组(或具有8字节字段的等效类型)。然而,这似乎是一个相当丑陋的解决方案,因为它最终要求您明确地拼出每个单独的字节。幸运的是,已经存在一种符合长度约束的原始类型:ulong
正如Marc建议的那样。