【发布时间】:2016-01-31 14:48:01
【问题描述】:
从度量单位转换为基础值类型并返回很容易:
[<Measure>]
type meter
module Meter =
let from m = m * 1</meter>
let too m = m * 1<meter>
但后来我想,一般来说,从一种基础类型到测量单位再转换回来不是很好吗?当然,我可以在每个实例上具体说明它,但我认为使用 cast-to 和 cast-from 运算符会很方便,同时保持类型安全。
我的第一次尝试:
[<AutoOpen>]
module Convert =
let inline (!->) x = x * 1<_> // (often) magically works
let inline (!-<) x = x * 1</_> // syntax error on the "/_"
!-> 运算符依靠类型推断工作。如果第二个运算符也可以工作,那就太好了,但不支持 /_ 语法。我尝试了一些类型注释的变体,但无法提出直接的通用解决方案,部分原因是我们无法编写 'T<'M> 或其某些变体。
然后我想到了使用用于隐式转换的技巧,但随后应用于显式转换,因为 'T<'M> 的基础类型如果 'T 和显式转换始终存在:
[<AutoOpen>]
module Convert =
let inline explicit_convert (x:^a) : ^b = ((^a or ^b) : (static member op_Explicit : ^a -> ^b) x)
let inline (::>) x = explicit_convert x // works both ways
这有一个额外的好处,它适用于任何具有显式转换运算符的类型。不幸的是,编译器抱怨这样做可能不安全:
名称为“op_Explicit”的成员约束由 F# 编译器赋予特殊状态,因为某些 .NET 类型通过该成员隐式扩充。如果您尝试从自己的代码中调用成员约束,这可能会导致运行时失败。
我不确定我是否走在正确的轨道上,或者是否有一种更安全的方法来创建可以从任何测量到基础类型并返回的运算符(包括复杂的测量,例如 int<meter ^ 4>或int<meter / sec ^ 2>)
【问题讨论】:
标签: generics f# type-conversion units-of-measurement