Elixir 是一门动态类型语言,也就是说,它不提供编译时的类型检查。不过,类型规范仍然很有用,因为它们:
使用@spec模块属性,可以在函数定义之前为函数添加类型规范。
@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
def longer_than?(string, length), do: String.length(string) > length
类型规范中允许使用的表达式:
基本类型,例如:
boolean()integer()、non_neg_integer()、pos_integer()、float()
list()map()any()联合类型:
integer() | list(integer())
参数化类型:
list(integer()),即整数列表%{age: integer()},即键:age对应整数值的映射远程类型(定义在某个模块中),例如:
字面量,例如:
%{},即空映射[],即空列表(但[any()]是非空列表):ok,即原子字面量内置的专用类型,例如:
char(),即0..0x10FFFF范围内的整数charlist(),即字符列表keyword(),即由二元组构成的列表,其中第一个元素是原子自定义类型
所有类型的完整列表可以在官方文档中的“Typespecs”一节中找到。
类型规范中的实参也可以命名,这在区分同一类型的多个实参时很有用。
@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()
可以使用以下三种模块属性之一来定义自定义类型:
@type,定义公开类型@typep,定义私有类型@opaque,定义结构私有的公开类型@type color :: {hue :: integer, saturation :: integer, lightness :: integer}
@spec to_hex(color()) :: String.t()
String.t()、binary()和string()的区别String.t()是用于 Elixir 字符串的正确类型,因为 Elixir 字符串是 UTF-8 编码的二进制。严格来说,String.t()被定义为binary(),对分析工具而言这两种类型是等价的,但在为处理 Elixir 字符串的函数编写文档时,String.t()更能体现意图。
另一方面,string()是另一种类型。它是 Erlang 字符串,在 Elixir 中称为字符列表。在类型规范中应避免使用string()类型,而应改用charlist()。
Dialyzer 是一款静态分析工具,可以检测 Erlang 和 Elixir 代码中的类型错误等问题。在 Elixir 项目中使用 Dialyzer 最简单的方式是借助 Dialyxir。