F # Единица измерения, Кастинг без потери типа меры
Есть ли встроенная версия функций литья типа, которая сохраняет единицы, и если не так, как бы я их создал? Так, например, с помощью этого кода, как бы я передал intWithSecondsMeasure в float без потери меры или умножения на 1.0<s>
?
[<Measure>] type s
let intWithSecondsMeasure = 1<s>
let justAFloat = float intWithSecondsMeasure
Ответы
Ответ 1
Ответ, предоставленный @kvb, безусловно, работает, но я бы предпочел не использовать оператор unbox
для этого преобразования. Там лучше, встроенный способ, который, по моему мнению, должен быть скомпилирован как NOP для IL (я не проверял, но unbox, вероятно, закончится как инструкция unbox
в IL и, таким образом, добавит проверку типа времени выполнения).
Предпочтительным способом преобразования единиц в F # является LanguagePrimitives.TypeWithMeasure
(MSDN).
let inline float32toFloat (x:float32<'u>) : float<'u> =
x |> float |> LanguagePrimitives.FloatWithMeasure
Ответ 2
Я не думаю, что есть встроенный способ сделать это, но вы можете легко определить свою собственную функцию преобразования единиц хранения:
let float_unit (x:int<'u>) : float<'u> = unbox float x
let floatWithSecondsMeasure = float_unit intWithSecondsMeasure
Ответ 3
Я скомпилировал код из ответов 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
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
kvb answer
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/[email protected]::.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
Ответ 4
См. мой ответ на этот вопрос:
Единичные квадратные корни
который предлагает это сегодня:
[<Measure>]
type s
let intWithSecondsMeasure = 1<s>
let intUtoFloatU< [<Measure>] 'u>( x : int<'u> ) : float<'u> = //'
let i = int x // drop the units
let f = float i // cast
box f :?> float<'u> //' restore the units
let floatWithS = intUtoFloatU intWithSecondsMeasure