在我查看以下问题时出现了这个问题:F# Unit of Measure, Casting without losing the measure type 请注意,我并没有尝试使用此unbox代码,我在回答问题时发现了一些奇怪的行为。
为什么以下代码可以正常工作
let intToFloat (x:int<'u>) : float<'u> = unbox float x
intToFloat 1<second>
虽然这会产生 System.InvalidCastException:无法将类型为'float32ToFloat @ 86-6'的对象强制转换为'Microsoft.FSharp.Core.FSharpFunc`2 [System.Single,System.Double]'。
let float32ToFloat (x:float32<'u>) : float<'u> = unbox float x
float32ToFloat 1.0f<second>
如果我在(float x)
周围放置了代码,代码按预期工作,那么我认为它必须是一些表达式评估/类型推断规则。这里究竟发生了什么,为什么第二种情况下需要这些鹦鹉?
答案 0 :(得分:3)
代码段中的细微内容是unbox float x
- 编译器将其视为(unbox float) x
。结果这两个函数实际上是这样处理的:
let intToFloat (x:int<'u>) : float<'u> =
let f = unbox float in f x
let float32ToFloat (x:float32<'u>) : float<'u> =
let f = unbox float in f x
所以,你正在使用float
函数,将它(不安全地)转换为另一种类型的函数,然后调用它。第一种情况下的类型为int<'u> -> float<'u>
,第二种情况下为float32<'u> -> float<'u>
。
我认为第一个可行,因为当编译器看到float
函数(没有任何类型注释)时,它默认为int -> float
,并且由于测量单位在运行时被擦除,这可能是转换为int<'u> -> float<'u>
(但不转换为第二种类型 - 因为您正在执行不安全的转换)。
因此,主要问题是您的实现中的错误括号(这会导致一个非常微妙的问题)。我想你可能想要这样的东西:
let intToFloat (x:int<'u>) : float<'u> = unbox (float x)
let float32ToFloat (x:float32<'u>) : float<'u> = unbox (float32 x)