类型之浅显易懂

Erlang是一种动态类型语言。这意味着任何变量,字段或函数参数可以包含任何允许的值。

类型规格说明

有一种类型描述语言,你可以用它来描述你认为你的函数应该有什么样的入参和返回值。这些类型规格说明是可选的,并且即使有不合适的类型存在,编译器也将好像没有任何事情发生一样运行你的程序。为了确认你的类型规格说明彼此没有冲突,我们可以使用另一个工具,它叫做Dialyzer。

在Erlang源文件里,一个类型规格说明就是一条命令,它看起来如下:

1
-spec func_name(Arg :: integer(), _, Y :: any()) -> float().

类型规格说明不是代码,它既不运行也不阻止你的程序被编译。

请参阅:
你可以在类型规格说明参考手册和其他已有的书籍,比如:Learn You Some Erlang 里读到更多关于类型规格说明的内容。

Dialyzer

Dialyzer把编译好的BEAM文件或Erlang源文件作为输入,然后尝试猜类型(类型推导)。

它是如何运作的

假设你已经写了一个函数f,它有一个入参X并且返回一些值。Dialyzer首先做一个大致的假设,f是一个fun(),它的入参是任何值((X :: any())并且返回任何值(any())。如下是Dialyzer一开始的猜测结果:

1
-spec f(X :: any()) -> any().

Any()是最宽泛的类型,它可能包括任何值。然后Dialyzer分析这个函数的用法和它的代码,并尝试缩小入参和返回值类型到更狭窄特定的类型集合。

例如,如果Dialyzer发现仅有两个地方调用你的函数,分别传入整数入参和原子入参,那么X的类型缩小到 integer()|atom() (一个两个类型的集合)。如下就是Dialyzer可能推断出来的结果:

1
-spec f(X :: integer() | atom()) -> any().

如果Dialyzer发现了一个矛盾,也就是一些类型其实合并后是一个空类型(none())或不兼容的类型被发现,Dialyzer会报告一个错误。这些错误看起来令人困惑,不过它们常常(还是一直?)指出代码中存在的问题。

Typer

Typer是另一个可选工具,在你的OTP环境里可以找到。Typer使用和Dialyzer一样的算法来推导给定模块里的各种类型并且打印它们。你可以把这些输出插入到你的程序里以备将来使用,或者为大的遗留项目做更好的文档。

原文链接: http://beam-wisdoms.clau.se/en/latest/eli5-types.html