类型别名不提供编译时类型检查
类型别名非常便于缩短长类型名称。类型别名'只是合成糖,在运行时被编译成别名类型,这意味着代表相同类型的两个不同别名可以互换使用而不会出错:
type foo = int
type bar = int
let x : foo = 5
let y : bar = x
type foo = int
type bar = int
val x : foo = 5
val y : bar = 5
我理解为什么你不希望将它们视为具有编译时类型实施的常规类型。不过,在某些情况下,它会非常方便。
有时,我需要区分代表不同内容的整数
例如,我从具有多种不同类型值的COM库导入一些函数,但它们在我的代码中都表示为int
:
[<DllImport(@"C:\API\COMAPI.dll", EntryPoint="Foobar")>]
extern int Foobar ( int hPool, int hServer )
在C中,hPool
的类型为APIP
且hServer
,函数返回类型均为APIV
:
typedef unsigned long API_INDEX; // index
typedef API_INDEX * APIV; // value handle
typedef void * APIP; // pool handle
我想用不同的类型来表示这些不同的类型,代表不同的东西,它们提供了一些编译时类型的实现。这样,我就不会意外地将APIP传递给期待APIV的函数。
措施让我在那里中途,但需要大量额外的绒毛
到目前为止,我发现的唯一解决方案是使用测量:
type [<Measure>] APIP
type [<Measure>] APIV
不幸的是,似乎无法直接向外部人员添加措施:
[<DllImport(@"C:\API\COMAPI.dll", EntryPoint="Foobar")>]
extern int<APIV> _Foobar ( int<APIP> hPool, int<APIV> hServer )
error FS0010: Unexpected type application in extern declaration. Expected identifier or other token.
所以我不得不编写一个包装函数,导致大量的额外代码:
[<DllImport(@"C:\API\COMAPI.dll", EntryPoint="Foobar")>]
extern int private _Foobar ( int hPool, int hServer )
let Foobar ( hPool : int<APIP> ) ( hServer : int<APIV> ) : APIV =
_Foobar( int hPool, int hServer ) |> LanguagePrimitives.Int32WithMeasure
乘以数十个和几十个导入的函数,这变得非常臃肿和厌倦。
有没有更直观的方法来解决这个问题,还是我决定在编译时类型检查和合理可读的代码之间做出决定?