类型

类型规格 属于 Elixir

1 个练习

关于 类型规格

Elixir 是一门动态类型语言,也就是说,它不提供编译时的类型检查。不过,类型规范仍然很有用,因为它们:

  • 可以充当文档。
  • 可以被 Dialyzer 这类静态分析工具用来找出可能的 bug。

使用@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

Dialyzer 是一款静态分析工具,可以检测 Erlang 和 Elixir 代码中的类型错误等问题。在 Elixir 项目中使用 Dialyzer 最简单的方式是借助 Dialyxir。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 类型规格