Elixir模式匹配进阶 #
一、case深入 #
1.1 基本模式 #
elixir
case value do
pattern1 -> result1
pattern2 -> result2
_ -> default_result
end
1.2 元组匹配 #
elixir
def handle_result(result) do
case result do
{:ok, data} ->
{:success, process(data)}
{:error, :not_found} ->
{:error, "Resource not found"}
{:error, :unauthorized} ->
{:error, "Unauthorized access"}
{:error, reason} ->
{:error, "Failed: #{reason}"}
end
end
1.3 列表匹配 #
elixir
def process_list(list) do
case list do
[] -> "Empty list"
[single] -> "Single element: #{single}"
[first, second] -> "Two elements: #{first}, #{second}"
[head | tail] -> "Head: #{head}, Tail length: #{length(tail)}"
end
end
1.4 映射匹配 #
elixir
def handle_user(user) do
case user do
%{role: :admin, name: name} ->
"Admin: #{name}"
%{role: :user, active: true, name: name} ->
"Active user: #{name}"
%{role: :user, active: false} ->
"Inactive user"
%{name: name} ->
"Unknown role: #{name}"
end
end
1.5 嵌套匹配 #
elixir
def handle_config(config) do
case config do
%{
database: %{host: host, port: port},
cache: %{enabled: true, ttl: ttl}
} ->
"DB: #{host}:#{port}, Cache TTL: #{ttl}"
%{
database: %{host: host, port: port},
cache: %{enabled: false}
} ->
"DB: #{host}:#{port}, No cache"
_ ->
"Invalid config"
end
end
1.6 二进制匹配 #
elixir
def parse_packet(data) do
case data do
<<1::size(8), length::size(16), payload::binary-size(length), rest::binary>> ->
{:ok, %{type: 1, payload: payload}, rest}
<<2::size(8), id::size(32), message::binary>> ->
{:ok, %{type: 2, id: id, message: message}, ""}
<<type::size(8), _rest::binary>> ->
{:error, "Unknown packet type: #{type}"}
end
end
二、守卫子句深入 #
2.1 基本语法 #
elixir
case value do
pattern when guard -> result
end
2.2 类型守卫 #
elixir
def process(value) do
case value do
x when is_integer(x) -> "Integer: #{x}"
x when is_float(x) -> "Float: #{x}"
x when is_binary(x) -> "String: #{x}"
x when is_list(x) -> "List with #{length(x)} elements"
x when is_map(x) -> "Map with #{map_size(x)} keys"
x when is_atom(x) -> "Atom: #{x}"
_ -> "Unknown type"
end
end
2.3 比较守卫 #
elixir
def categorize_number(n) do
case n do
x when x < 0 -> "Negative"
0 -> "Zero"
x when x > 0 and x < 10 -> "Small positive"
x when x >= 10 and x < 100 -> "Medium positive"
x when x >= 100 -> "Large positive"
end
end
2.4 列表守卫 #
elixir
def process_list(list) do
case list do
[] -> "Empty"
[_] -> "Single element"
[_, _] -> "Two elements"
list when length(list) > 10 -> "Long list"
_ -> "Normal list"
end
end
2.5 多条件守卫 #
elixir
def validate_user(user) do
case user do
%{age: age} when age >= 18 and age <= 65 ->
{:ok, "Working age"}
%{age: age} when age < 18 ->
{:error, "Too young"}
%{age: age} when age > 65 ->
{:ok, "Retirement age"}
_ ->
{:error, "Invalid user"}
end
end
2.6 成员检查守卫 #
elixir
def handle_role(role) do
case role do
r when r in [:admin, :super_admin] -> :full_access
r when r in [:moderator, :editor] -> :limited_access
:user -> :basic_access
_ -> :no_access
end
end
三、with表达式 #
3.1 基本语法 #
with 用于链式模式匹配,任一匹配失败则提前退出:
elixir
with pattern1 <- expr1,
pattern2 <- expr2,
pattern3 <- expr3 do
success_block
else
pattern4 -> error_block
end
3.2 基本示例 #
elixir
iex(1)> with {:ok, a} <- {:ok, 1},
...> {:ok, b} <- {:ok, 2},
...> {:ok, c} <- {:ok, 3} do
...> a + b + c
...> end
6
3.3 提前退出 #
elixir
iex(1)> with {:ok, a} <- {:ok, 1},
...> {:error, reason} <- {:error, "failed"},
...> {:ok, c} <- {:ok, 3} do
...> a + c
...> else
...> {:error, reason} -> {:error, reason}
...> end
{:error, "failed"}
3.4 实际应用 #
elixir
defmodule UserService do
def register_user(params) do
with {:ok, validated} <- validate_params(params),
{:ok, user} <- create_user(validated),
{:ok, token} <- generate_token(user),
{:ok, _} <- send_welcome_email(user) do
{:ok, %{user: user, token: token}}
end
end
defp validate_params(params) do
if params[:email] && params[:password] do
{:ok, params}
else
{:error, :invalid_params}
end
end
defp create_user(params) do
{:ok, %{id: 1, email: params[:email]}}
end
defp generate_token(user) do
{:ok, "token-#{user.id}"}
end
defp send_welcome_email(user) do
{:ok, :sent}
end
end
3.5 else子句 #
elixir
def fetch_and_process(user_id) do
with {:ok, user} <- fetch_user(user_id),
{:ok, posts} <- fetch_posts(user),
{:ok, comments} <- fetch_comments(posts) do
{:ok, %{user: user, posts: posts, comments: comments}}
else
{:error, :not_found} ->
{:error, "User not found"}
{:error, :no_posts} ->
{:ok, %{user: user, posts: [], comments: []}}
{:error, reason} ->
{:error, reason}
end
end
3.6 无else子句 #
如果没有else子句,失败的值会直接返回:
elixir
iex(1)> with {:ok, x} <- {:error, :not_found} do
...> x * 2
...> end
{:error, :not_found}
3.7 with与模式匹配 #
elixir
def process_config(config) do
with {:ok, host} <- Map.fetch(config, :host),
{:ok, port} <- Map.fetch(config, :port),
{:ok, db} <- Map.fetch(config, :database) do
{:ok, %{host: host, port: port, database: db}}
else
:error -> {:error, "Missing configuration"}
end
end
四、函数头守卫 #
4.1 多子句函数 #
elixir
defmodule Math do
def abs(x) when x < 0, do: -x
def abs(x), do: x
def sign(x) when x > 0, do: 1
def sign(x) when x < 0, do: -1
def sign(0), do: 0
def factorial(0), do: 1
def factorial(n) when n > 0, do: n * factorial(n - 1)
end
4.2 参数模式匹配 #
elixir
defmodule ListUtils do
def first([head | _]), do: head
def first([]), do: nil
def last([x]), do: x
def last([_ | tail]), do: last(tail)
def last([]), do: nil
def nth([head | _], 0), do: head
def nth([_ | tail], n) when n > 0, do: nth(tail, n - 1)
def nth([], _), do: nil
end
4.3 复杂守卫 #
elixir
defmodule Validator do
def validate(%{email: email, password: password})
when is_binary(email) and is_binary(password) and byte_size(password) >= 8 do
{:ok, %{email: email, password: password}}
end
def validate(%{email: _, password: password}) when byte_size(password) < 8 do
{:error, "Password too short"}
end
def validate(_) do
{:error, "Invalid input"}
end
end
五、模式匹配最佳实践 #
5.1 优先使用模式匹配 #
elixir
def bad_example(user) do
if user[:role] == :admin do
if user[:active] do
"Active admin"
else
"Inactive admin"
end
else
"Not admin"
end
end
def good_example(user) do
case user do
%{role: :admin, active: true} -> "Active admin"
%{role: :admin} -> "Inactive admin"
_ -> "Not admin"
end
end
5.2 使用with处理链式操作 #
elixir
def bad_example(params) do
case validate(params) do
{:ok, validated} ->
case create(validated) do
{:ok, created} ->
case notify(created) do
{:ok, _} -> {:ok, created}
error -> error
end
error -> error
end
error -> error
end
end
def good_example(params) do
with {:ok, validated} <- validate(params),
{:ok, created} <- create(validated),
{:ok, _} <- notify(created) do
{:ok, created}
end
end
5.3 使用守卫简化逻辑 #
elixir
def bad_example(list) do
if is_list(list) and length(list) > 0 do
hd(list)
else
nil
end
end
def good_example([head | _]), do: head
def good_example([]), do: nil
六、总结 #
本章学习了:
| 特性 | 用途 |
|---|---|
| case | 多分支模式匹配 |
| 守卫子句 | 模式匹配中的条件约束 |
| with | 链式模式匹配 |
| 函数头守卫 | 函数参数验证 |
准备好学习函数了吗?让我们进入下一章。
最后更新:2026-03-27