F#能强制一个参数为byte[8]吗?

3

我需要一个小型实用函数,从8字节数组生成校验和。

这本身很简单,但在C#中,我不能使用byte Checksum(byte[8] input)作为方法声明-我无法指定数组大小,因此必须使用可以是任何大小的byte[],然后在方法体中,我需要检查输入不为空且长度== 8。

我想知道F#是否能够做到这一点?我听说F#有更多选项来限制函数的可接受参数(例如,辨别联合)?

当然,在这个微不足道的例子中,F#会过度杀伤,但我很好奇。

4个回答

4
假设您不希望调用者单独传递它们,那么 byte[] 参数在我看来是可以的;唯一要做的更改是考虑传递起始偏移量(因为我经常发现自己从 byte[] 的开头开始工作——但这取决于上下文)。
如果您真的想避免这种丑陋,您可以考虑将其视为 long(或者由于负数的右移而更好: ulong)。您总是知道它的长度恰好为 8 个字节,并且它还避免了一些查找。
您可以通过移位或通过 byte*ulong* 的不安全转换在两种格式之间切换。

3

我认为正确的做法是创建一个包装byte[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"

在C#中,你应该做同样的事情 - 将字节数组封装在一个类型中。 - plinth

2

两种语言都不能指定函数接受特定长度的数组。这个问题在于要检查调用者是否实际提供了具有该长度的数组相当困难。可以通过直接创建 new byte[8] 时检查,但其他所有情况都需要一些巧妙的技巧。

这部分工作由Code Contracts完成,它是一种用于附加检查的工具,可安装到Visual Studio中并与C#和F#一起使用。它允许你编写类似如下的代码:

byte CheckSum(byte[] data) {
  Contract.Requires(data != null);
  Contract.Requires(data.Length == 8);
  // Implementation
}

代码合约配备了一个工具,可以在编译时警告您调用大小不正确的数组时调用CheckSum。它还可以生成运行时检查(当无法静态确定调用是否正确时)。


1
在F#(或任何其他.NET语言)中,类型不能依赖于值,因此答案是否定的,你不能这样做。(请注意,你可以在C++模板中编码它,因为模板可以依赖于整数参数。)仅使用byte[]的包装器类型只是将运行时长度检查转移到包装器对象的构造中,并没有真正改善情况。
我能想到的唯一强制在编译时使用正确类型的方法是使用8元组(或具有八个字节字段的等效类型)。然而,这似乎是一个相当丑陋的解决方案,因为最终需要明确拼出每个单独的字节。幸运的是,已经有一个满足长度约束的原始类型:ulong,就像Marc建议的那样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接