【问题标题】:F# 'unbox float x' vs. 'unbox int x' weird compilation resultF# 'unbox float x' vs. 'unbox int x' 奇怪的编译结果
【发布时间】:2014-03-14 21:54:35
【问题描述】:

这是在我查看以下问题时出现的:F# Unit of Measure, Casting without losing the measure type 请注意,我并没有尝试使用此拆箱代码,我只是在回答问题时发现了一些奇怪的行为。

为什么下面的代码会起作用

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) 周围加上括号,代码会按预期工作,所以我认为它一定是某种表达式评估/类型推断规则。这里到底发生了什么,为什么在第二种情况下需要括号?

【问题讨论】:

  • 托马斯的回答解释了错误,但作为旁注,unbox 不是最好的方法。您应该使用LanguagePrimitives.FloatWithMeasure&lt;'u&gt;,它转换为.NET 字节码中的无操作,而unbox 添加了一些在这种情况下不需要的运行时类型检查。
  • @Tarmil,我知道这一点。感谢您确认FloatWithMeasure 是一个更好的选择(请参阅我对链接问题的回答)。你介意在那里添加/确认吗?
  • 哦,我在您链接的问题中没有看到您的帖子。所以我们几乎说了同样的话:)

标签: f# type-inference units-of-measurement


【解决方案1】:

您的代码 sn-ps 中的微妙之处是 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&lt;'u&gt; -&gt; float&lt;'u&gt;,第二种情况是float32&lt;'u&gt; -&gt; float&lt;'u&gt;

我认为第一个有效,因为当编译器看到float 函数(没有任何类型注释)时,它默认为int -&gt; float,并且由于测量单位在运行时被删除,因此可以将其转换为@987654329 @ (但不是第二种类型 - 因为你正在执行不安全的演员表)。

因此,主要问题是您的实现中的括号错误(这会导致一个非常微妙的问题)。我想你可能想要这样的东西:

let intToFloat (x:int<'u>) : float<'u> = unbox (float x)
let float32ToFloat (x:float32<'u>) : float<'u> = unbox (float32 x)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 2014-04-16
    相关资源
    最近更新 更多