我如何在F#中无需测量的情况下创建一个测量的记录类型



我已经在公共库(libroot)中定义了一个记录类型,该记录类型均由C#(libc)和F#(libf)代码使用。

i然后在f#库(libf)消耗的C#库(LIBC)中写了一个公共API。但是,每当我试图将对象传递给此API F#时,都认为它必须具有一个度量单位。

//LibRoot - F#
type Vec2<[Measure] 'u> = {
    X : int
    Y : int
}
//LibC - C#
public static class Funcs
{
    public void DoWork(Vec2 vec) { //no measure needed in C#
        ....
    }
}
//LibF - F#
open LibC
let myVec : Vec2<1> = { X = 123; Y = 456 }
DoWork(myVec) //FS0001

错误FS0001:键入不匹配。期望一个" vec2",但给出了" vec2&lt; 1>"。不同的长度为0和1

我尝试过:

  • Vec2<1>:FS0001
  • Vec2<0>:类型中无效的文字
  • Vec2<()>:意外')'
  • Vec2<_>:FS0001
  • Vec2<unit>:预期的度量单位,不是类型
  • (Vec2) myVec:没有可用于'vec2&lt;'u>
  • 的构造函数

是否有人知道一种以互惠方式构造测量的记录类型的方法?

如注释中所述,度量单位是f# - 仅在编译的.NET代码中没有表示的功能,因此当您使用C#的单位声明类型时,它将显示为没有单位的类型。

编译的C#代码将不包含特殊的F#meta-data,以表明这是单位声明的类型,因此F#编译器引用您的C#库不会将其识别为单位声明类型。可以说,F#编译器可以更聪明并弄清楚这一点(因为它可以确定Vec2类型最初来自F#)。

我认为没有一种安全的方法可以将未测量的Vec2转换为测量的Vec2<_>,但是使用unbox的不安全转换将在运行时起作用:

let v : LibRoot.Vec2<1> = { LibRoot.Vec2.X = 1; Y = 2 }
LibCs.Funcs.DoWork(unbox v)

我认为在F#代码中明确指出Vec2类型(无需测量)的方法没有一种方法,但是unbox不断添加该类型的罚款。这不是很好,因此,如果您经常需要此转换,则最好重新设计库,以便C#使用没有单位的单独类型。

tomas的答案是正确的。我将分享我的解决方法。

我的度量单位是

 [<Measure>] type Absolute
 [<Measure>] type Relative 

我引入了可转换为Vec2<>的"混凝土"记录类型。例如

type Offset2 = { 
   X : int
   Y : int 
}
   with 
       static member ofVec (vec : Vec2<Relative>) : Offset2 = { X = vec.X; Y = vec.Y }
       static member toVec (off: Offset2) : Vec2<Relative> = { X = off.X; Y = off.Y }

我将它们转换为VEC2以执行数学,但将"混凝土"类型用于公共API。拥有额外的类型有点烦人。

最新更新