Elixir类型规范 #
一、类型规范概述 #
1.1 什么是类型规范 #
类型规范是函数的类型签名,用于文档和静态分析。
1.2 为什么使用类型规范 #
- 提供文档
- 静态分析
- IDE支持
- 代码质量
二、基本类型 #
2.1 内置类型 #
elixir
any()
atom()
binary()
bitstring()
boolean()
byte()
char()
float()
function()
integer()
list()
map()
number()
pid()
port()
reference()
tuple()
2.2 字面量类型 #
elixir
:ok
:error
nil
true
false
2.3 集合类型 #
elixir
list(type)
nonempty_list(type)
maybe_improper_list(type1, type2)
[type]
[type, ...]
2.4 元组类型 #
elixir
tuple()
{type1, type2, ...}
{:ok, term()}
{:error, atom()}
2.5 映射类型 #
elixir
map()
%{key_type => value_type}
%{required_key: type, optional_key?: type}
2.6 函数类型 #
elixir
(... -> type)
(type1, type2 -> type)
三、@spec #
3.1 基本语法 #
elixir
@spec function_name(param_types) :: return_type
3.2 示例 #
elixir
defmodule Math do
@spec add(number(), number()) :: number()
def add(a, b), do: a + b
@spec divide(number(), number()) :: {:ok, number()} | {:error, :division_by_zero}
def divide(_, 0), do: {:error, :division_by_zero}
def divide(a, b), do: {:ok, a / b}
@spec factorial(non_neg_integer()) :: pos_integer()
def factorial(0), do: 1
def factorial(n), do: n * factorial(n - 1)
end
3.3 多个子句 #
elixir
defmodule String do
@spec split(binary()) :: [binary()]
@spec split(binary(), binary()) :: [binary()]
@spec split(binary(), binary(), keyword()) :: [binary()]
def split(string, pattern \\ " ", opts \\ [])
end
四、@type #
4.1 定义类型 #
elixir
defmodule User do
@type id :: integer()
@type name :: String.t()
@type email :: String.t()
@type t :: %__MODULE__{
id: id(),
name: name(),
email: email()
}
defstruct [:id, :name, :email]
end
4.2 使用自定义类型 #
elixir
defmodule UserService do
@spec create(User.name(), User.email()) :: User.t()
def create(name, email) do
%User{name: name, email: email}
end
@spec find(User.id()) :: User.t() | nil
def find(id) do
# ...
end
end
4.3 @typep #
私有类型:
elixir
defmodule Internal do
@typep internal_id :: integer()
@spec process(internal_id()) :: :ok
def process(id), do: :ok
end
4.4 @opaque #
不透明类型:
elixir
defmodule Handle do
@opaque t :: reference()
@spec new() :: t()
def new, do: make_ref()
end
五、约束 #
5.1 guard约束 #
elixir
@spec pos_number(number()) :: number() when number: number()
@spec my_func(arg) :: result when arg: integer(), result: float()
5.2 使用示例 #
elixir
defmodule Bounded do
@type bounded(a) :: a when a: number()
@spec in_range(bounded(number()), number(), number()) :: boolean()
def in_range(value, min, max) do
value >= min and value <= max
end
end
六、行为规范 #
6.1 @callback #
elixir
defmodule Parser do
@callback parse(String.t()) :: {:ok, term()} | {:error, term()}
@callback format(term()) :: String.t()
end
6.2 @macrocallback #
elixir
defmodule MyBehaviour do
@macrocallback my_macro(term()) :: Macro.t()
end
6.3 实现行为 #
elixir
defmodule JsonParser do
@behaviour Parser
@impl true
def parse(string), do: Jason.decode(string)
@impl true
def format(data), do: Jason.encode(data)
end
七、Dialyzer #
7.1 安装 #
Dialyzer是Erlang/OTP的一部分,无需额外安装。
7.2 配置 #
elixir
# mix.exs
def project do
[
app: :my_app,
version: "0.1.0",
dialyzer: [
plt_add_apps: [:mix],
flags: [:unmatched_returns, :error_handling, :race_conditions]
]
]
end
7.3 运行 #
bash
mix dialyzer
7.4 常见警告 #
no_return- 函数没有返回no_unused- 未使用的变量pattern_match- 模式匹配问题type_error- 类型错误
八、类型规范最佳实践 #
8.1 完整示例 #
elixir
defmodule Bank.Account do
@type id :: pos_integer()
@type balance :: non_neg_integer()
@type currency :: :USD | :EUR | :GBP
@type t :: %__MODULE__{
id: id(),
balance: balance(),
currency: currency()
}
defstruct [:id, :balance, :currency]
@spec new(currency()) :: t()
def new(currency \\ :USD) do
%__MODULE__{id: generate_id(), balance: 0, currency: currency}
end
@spec deposit(t(), pos_integer()) :: t()
def deposit(%__MODULE__{balance: balance} = account, amount) do
%{account | balance: balance + amount}
end
@spec withdraw(t(), pos_integer()) :: {:ok, t()} | {:error, :insufficient_funds}
def withdraw(%__MODULE__{balance: balance} = account, amount) do
if balance >= amount do
{:ok, %{account | balance: balance - amount}}
else
{:error, :insufficient_funds}
end
end
@spec balance(t()) :: balance()
def balance(%__MODULE__{balance: balance}), do: balance
defp generate_id, do: :rand.uniform(1_000_000)
end
九、总结 #
本章学习了:
| 特性 | 用途 |
|---|---|
@spec |
函数类型规范 |
@type |
公开类型定义 |
@typep |
私有类型定义 |
@opaque |
不透明类型 |
@callback |
行为回调规范 |
| Dialyzer | 静态分析工具 |
准备好学习框架了吗?让我们进入下一章。
最后更新:2026-03-27