F#计量单位,在不丢失测量类型的情况下进行铸造

gra*_*bot 13 f# casting units-of-measurement

是否有内置版本的类型转换功能可以保留单位,如果没有,我将如何制作它们?因此,例如使用此代码,如何将intWithSecondsMeasure转换为浮点数而不会丢失度量或乘以1.0<s>

[<Measure>] type s
let intWithSecondsMeasure = 1<s>
let justAFloat = float intWithSecondsMeasure 
Run Code Online (Sandbox Code Playgroud)

Joh*_*lph 11

@kvb提供的答案肯定有效,但我不想使用unbox运算符进行此转换.有一个更好的,内置的方式,我认为应该编译为IL的NOP(我没有检查,但unbox可能最终作为unboxIL中的指令,因此添加运行时类型检查).

在F#中进行单位转换的首选方法是LanguagePrimitives.TypeWithMeasure(MSDN).

let inline float32toFloat (x:float32<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure
Run Code Online (Sandbox Code Playgroud)


kvb*_*kvb 8

我认为没有内置的方法可以做到这一点,但您可以轻松定义自己的单元保留转换功能:

let float_unit (x:int<'u>) : float<'u> = unbox float x
let floatWithSecondsMeasure = float_unit intWithSecondsMeasure
Run Code Online (Sandbox Code Playgroud)


gra*_*bot 5

我从 kvb 和 Johannes 的答案中编译了代码。

约翰内斯回答

let float32toFloat (x:int<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure

.method public static float64  float32toFloat(int32 x) cil managed
{
  // Code size       3 (0x3)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  ret
} // end of method Program::float32toFloat
Run Code Online (Sandbox Code Playgroud)

添加括号的 kvb 答案。

let float_unit (x:int<'u>) : float<'u> = unbox (float x)

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  box        [mscorlib]System.Double
  IL_0007:  unbox.any  [mscorlib]System.Double
  IL_000c:  ret
} // end of method Program::float_unit
Run Code Online (Sandbox Code Playgroud)

回答

let float_unit (x:int<'u>) : float<'u> = unbox float x

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       19 (0x13)
  .maxstack  8
  IL_0000:  newobj     instance void Program/float_unit@4::.ctor()
  IL_0005:  call       !!0 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::UnboxGeneric<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>>(object)
  IL_000a:  ldarg.0
  IL_000b:  tail.
  IL_000d:  callvirt   instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>::Invoke(!0)
  IL_0012:  ret
} // end of method Program::float_unit
Run Code Online (Sandbox Code Playgroud)