13.4.2.1 使用计量单位
在 F# 中,使用计量单位很容易,这就是为什么我们在这一章看只是简单地介绍一下的原因。声明计量使用 type 关键字,加专有的特性。严格地说,计量并不是类型,但我们可以将其用作为另一种类型的部分使用。我们首先定义两个简单的计量,表示公里和小时:
[<Measure>] type km
[<Measure>] type h
可以发现,使用 Measure 特性描述的类型是计量。这是一个专有特性,F# 编译器能够理解。我们不一定要自己定义单位,可以使用 FSharp.PowerPack.dll 库中的标准集,但是现在,我们将自己声明。有了单位 km 和 h 以后,就可以创建表示公里或小时的值了。清单 13.15 显示了创建带单位的值,并写一个函数,用这些参与计算。
清单13.15 使用计量单位的计算 (F#)
> let length = 9.0<km>;; [1]
val length : float<km> = 9.0
> length * length;; [2]
val it : float<km^2> = 81.0
> let distanceInTwoHours(speed:float<km/h>) = [3]
speed * 2.0<h>;;
val distanceInTwoHours : float<km/h> -> float<km> [4]
> distanceInTwoHours(30.0<km/h>);;
val it : float<km> = 60.0
描述数值常量的单位时,值的后面加上括在尖括号角中的单位[1]。我们首先定义了一个表示在长度的值,以公里计。如果计算使用带单位的值,F# 能自动推断出结果的单位,因此,可以发现,距离乘了两次,得出的面积以平方公里计[2]。描述单位时,可以使用常规表示,即,用 ^ 表示乘方,用 / 表示除法,乘法写成并列单位。
下一个示例表明,函数的参数可以包括单位信息。我们的示例函数的参数为速度,返回两小时行走的路程[3]。我们指定参数以公里每小时计,因此,增加了包含单位的类型注解,把单位放在尖括号中,与指定类型参数值时的方式相同,比如 list 类型。F# 编译器能够推断出返回的类型[4],就像处理普通类型一样。通常,当我们阅读代码时,能够为我们理解函数功能提供线索;另外,这也是写函数时重要的检查,可以避免犯低级错误:如果我们试图计算距离,但最后返回类型的单位是时间,那就肯定错了。
在世界银行的数据中,我们将使用 km^2 表示国家总面积的单位。到目前为止,一切顺利,但是,我们想要的第二个指标是以百分比的形式提供的,那么,应该如何指定百分比的单位呢?虽然,计量单位主要是用来表示物理量的,但也可以用它们来表示百分比:
[<Measure>] type percent
let coef = 33.0<percent>
这段代码创建表示百分比的单位,然后,定义了常量 coef,是值的 33%。严格地说,以百分比计的值没有单位,因为,这是一个系数,把它定义成单位很有用。为了演示,我们计算 50 公里距离的 33%。由于 coef 表示系数,可以简单地把两个值乘起来:
> 50.0<km> * coef;;
val it : float<km percent> = 1650.0
很明显这是错误的。我们期望的结果以公里计,但是,从推导出的类型可以发现,结果是以公里乘以新的单位 percent。另外,从交互运行的代码还可以看到,数值太大,而计量单位的重要性就在于,我们可以在类型检查期间就发现错误,而不必等到程序实际运行时。那么,哪里出问题了呢?百分比值表示系数乘以 100;要正确写出计算,需要把值除以 100 percent:
> 50.0<km> * coef / 100.0<percent>;;
val it : float<km> = 16.5
可以发现,现在好多了。结果除以 100 percent,这样,在结果中就没有 percent单位了。F# 自动化简单位,知道 km percent/percent 等于 km。此示例演示了使用计量单位的重要原因:就像其他类型一样,能够有帮于尽早捕获大量的错误。
注意
计量单位还有很多其他重要的功能,在这个简介中我们没有涉及到。例如,可以定义派生单位,比如 N(表示力,以牛顿计),这实际上就是 kg m/s^2;在函数或类型中,泛型类型参数使用单位,也是可能的。有关计量单位的详细信息,请参阅 F# 联机文档,和架构师 Andrew Kennedy 关于该功能的博客(http://blogs.msdn.com/andrewkennedy)。
现在,我们回到主要的示例,把下载的数据转换成有单位的类型化形式。我们将使用原子单位 percent 表示地区森林覆盖,用单位 km^2 表示面积。
原文地址:http://blog.csdn.net/hadstj/article/details/44151233