- A+
原文 https://fsharpforfunandprofit.com/posts/overview-of-types-in-fsharp/
这个特性我觉得也比较新鲜,以前没有见过,先看代码吧:
type Dollar = Dollar of int let earn d:Dollar = d + 10 // Error
虽然只有两行代码,但有不少值得说明的地方。
第一行,有两个 Dollar
, 但它们有不同的含义,也只能用在不同的地方。第一个 Dollar
是一个类型,而第二个 Dollar
不是类型而是 union case, 这里只是故意重名,以便在两种场合都能使用 Dollar 这个单词。
因此,第二行代码里的 Dollar 是类型,此时,第二行会报错,因为类型 Dollar 不能与类型 int 直接相加。
我们把其中一个 Dollar
改成别的单词,就可以看得更清楚:
type Money = Dollar of int let earn d:Dollar = d + 10 // Error
这样,由于第一个 Dollar 已经改成 Money, 因此 Dollar 再也不能当作类型来使用,第二行会报错,而这次的错误原因是 “Dollar 不是类型”。
再看下面的代码:
// single case union type Dollar = Dollar of int let earn (Dollar d) = d + 10 // OK
上面的代码,第二行,就用到了我说的新鲜特性,这里的 Dollar 不是类型,而是 union case, 同时,由于 union case 可以用于 pattern match, 根据 pattern match 的原理,(Dollar d)
正是一个 pattern, 即 (Dollar int)
, 因此,d
的类型就是 int.
由于 d
的类型是 int, 因此可以与 10 相加,这次代码不会报错。
值得一提的是,这里发生 pattern match 的地方是一个函数的参数!
更神奇的是,这里 (Dollar int)
同时兼具两个作用:
-
限定了该参数的类型是
Dollar
, 如果输入一个 int 或别的类型,会报错,从而确保了类型安全。 -
unpacking/deconstruct, “顺便” 从这个参数里把
Dollar
的内涵数据 int 给解构出来了。
本文介绍了 F# 的一个有趣的特性(unpacking/deconstruct), 该特性表面上看着简单,背后却涉及 type 与 union case 的区别,以及 pattern match 的用法。