简体   繁体   English

F#可以强制参数为byte [8]吗?

[英]Can F# force a parameter to be byte[8]?

I need a little utility function that generates a checksum from an array of 8 bytes. 我需要一个小实用程序函数,从8个字节的数组生成校验和。

Now, this itself is trivial, except that I can't use byte Checksum(byte[8] input) in C# as a method declaration - I can't specify size of array, so I have to use byte[] which can be any size, and in the method body I then need to check that input is not null and length == 8. 现在,这本身是微不足道的,除了我不能在C#中使用byte Checksum(byte[8] input)作为方法声明 - 我不能指定数组的大小,所以我必须使用byte []这可以是任何大小,然后在方法体中,我需要检查输入是否为null,长度== 8。

I'm just wondering if F# can do that? 我只是想知道F#是否可以做到这一点? I heard that F# has a lot more options to limit acceptable parameters to a function (eg, Discriminated Unions)? 我听说F#有很多选项来限制函数的可接受参数(例如,判别联盟)?

Granted, in this trivial example F# would be overkill, but I'm curious. 当然,在这个简单的例子中,F#会有点矫枉过正,但我​​很好奇。

Assuming you don't want the caller to pass them in separately, the byte[] arg is IMO fine; 假设您不希望调用者单独传递它们,则byte[] arg是IMO罚款; the only change I'd make is that I'd consider passing in a start offset too (since I often find myself working away from the start of a byte[] - but it depends on your context). 我所做的唯一改变是我也考虑传入一个起始偏移量(因为我经常发现自己从一个byte[]的开始处起作用byte[] - 但这取决于你的上下文)。

If you really want to avoid this ugliness, you could consider treating it as a long (or arguably better (because of right-shift of negatives) for bit-work: ulong ). 如果你真的想避免这种丑陋,你可以考虑把它当作一个long (或者可以说是更好的(因为负面的权利转移)用于比特工作: ulong )。 You always know that is exactly 8 bytes in length, and it avoids a few lookups to boot. 你总是知道它的长度恰好是8个字节,它避免了一些启动查找。

You can switch between the two formats either by shifting or by unsafe cast of a byte* and ulong* 您可以通过移位或通过byte*ulong*不安全强制转换来切换这两种格式

I would say the proper way to go about it would be to create a type that wraps a byte[8] and use that as a parameter. 我会说去它的正确方法是创建一个type ,它包装一个byte [8]和使用,作为一个参数。


With that said, I can think of using active patterns, but seems like overkill: 话虽如此,我可以考虑使用活动模式,但看起来有点矫枉过正:

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"

Neither of the two languages can specify that a function takes an array of specific length. 这两种语言都不能指定函数采用特定长度的数组。 The problem with this is that checking whether the caller actually provides array with that length is quite difficult. 这个问题是检查调用者是否实际提供具有该长度的数组是非常困难的。 It can be checked when the array is created directly by new byte[8] , but all other cases require some tricky techniques. 可以检查何时直接由new byte[8]创建数组,但所有其他情况都需要一些棘手的技术。

This is partly done by Code Contracts , which is a tool for additional checking that can be installed into Visual Studio and used with both C# and F#. 这部分是由Code Contracts完成的, Code Contracts是一个可以安装到Visual Studio中并与C#和F#一起使用的附加检查工具。 It allows you to write something like: 它允许你写一些像:

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

Code Contracts come with a tool that gives you a warning at compile-time when you call CheckSum with a wrongly sized array. 代码契约附带了一个工具,当您使用错误大小的数组调用CheckSum时,该工具会在编译时向您发出警告。 It can also generate runtime check (when it cannot statically determine that the call is correct). 它还可以生成运行时检查(当它无法静态确定调用是否正确时)。

In F# (or any other .NET language) a type cannot depend on a value, therefore the answer is no, you can't do that. 在F#(或任何其他.NET语言)中,类型不能依赖于某个值,因此答案是否定的,您不能这样做。 (Note that you could encode that in a C++ template, as templates can depend on integer parameters.) Using a wrapper type for byte[] merely shifts the runtime length check to the construction of the wrapper object and doesn't really improve the situation. (请注意,您可以在C ++模板中对其进行编码,因为模板可以依赖于整数参数。)对于byte []使用包装器类型只是将运行时长度检查转换为包装器对象的构造,并没有真正改善情况。

The only way for actually forcing the correct type at compile time I can think of is using a 8-tuple (or an equivalent type with eight byte fields). 在编译时实际强制正确类型的唯一方法我可以想到使用8元组(或具有8字节字段的等效类型)。 That however seems to be an rather ugly solution as it ultimately requires you to spell out explicitly each of the individual bytes. 然而,这似乎是一个相当丑陋的解决方案,因为它最终要求您明确地拼出每个单独的字节。 Luckily there already is a primitive type that fulfills the length constraint: ulong as Marc suggested. 幸运的是已经有满足所述长度约束原始类型: ulong作为马克建议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM