Elixir模式匹配 #
一、匹配操作符 #
1.1 基本概念 #
Elixir使用 = 作为匹配操作符,而非赋值操作符:
elixir
iex(1)> x = 1
1
iex(2)> 1 = x
1
iex(3)> 2 = x
** (MatchError) no match of right hand side value: 1
1.2 匹配规则 #
左边是模式,右边是值,匹配成功则绑定变量:
elixir
iex(1)> {a, b, c} = {1, 2, 3}
{1, 2, 3}
iex(2)> a
1
iex(3)> b
2
iex(4)> c
3
1.3 单向匹配 #
匹配是单向的,右边不能包含未绑定变量:
elixir
iex(1)> {a, b} = {1, 2}
{1, 2}
iex(2)> {a, b} = {1, c}
** (CompileError) undefined variable "c"
二、元组匹配 #
2.1 基本匹配 #
elixir
iex(1)> {a, b, c} = {1, 2, 3}
{1, 2, 3}
iex(2)> {a, b} = {1, 2, 3}
** (MatchError) no match of right hand side value: {1, 2, 3}
2.2 忽略值 #
使用 _ 忽略不需要的值:
elixir
iex(1)> {a, _, c} = {1, 2, 3}
{1, 2, 3}
iex(2)> a
1
iex(3)> c
3
2.3 嵌套匹配 #
elixir
iex(1)> {a, {b, c}} = {1, {2, 3}}
{1, {2, 3}}
iex(2)> a
1
iex(3)> b
2
iex(4)> c
3
2.4 常见模式 #
elixir
iex(1)> {:ok, result} = {:ok, "Success"}
{:ok, "Success"}
iex(2)> result
"Success"
iex(3)> {:error, reason} = {:error, "Not found"}
{:error, "Not found"}
iex(4)> reason
"Not found"
三、列表匹配 #
3.1 头尾匹配 #
elixir
iex(1)> [head | tail] = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex(2)> head
1
iex(3)> tail
[2, 3, 4, 5]
3.2 多元素匹配 #
elixir
iex(1)> [a, b | rest] = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex(2)> a
1
iex(3)> b
2
iex(4)> rest
[3, 4, 5]
3.3 空列表匹配 #
elixir
iex(1)> [] = []
[]
iex(2)> [head | tail] = []
** (MatchError) no match of right hand side value: []
3.4 递归处理列表 #
elixir
defmodule ListUtils do
def sum([]), do: 0
def sum([head | tail]), do: head + sum(tail)
def length([]), do: 0
def length([_ | tail]), do: 1 + length(tail)
def map([], _func), do: []
def map([head | tail], func), do: [func.(head) | map(tail, func)]
end
四、映射匹配 #
4.1 基本匹配 #
elixir
iex(1)> %{name: name, age: age} = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> name
"Alice"
iex(3)> age
30
4.2 部分匹配 #
映射匹配只需要匹配存在的键:
elixir
iex(1)> %{name: name} = %{name: "Alice", age: 30, city: "NYC"}
%{age: 30, city: "NYC", name: "Alice"}
iex(2)> name
"Alice"
4.3 嵌套匹配 #
elixir
iex(1)> %{address: %{city: city}} = %{name: "Alice", address: %{city: "NYC", zip: "10001"}}
%{address: %{city: "NYC", zip: "10001"}, name: "Alice"}
iex(2)> city
"NYC"
4.4 动态键匹配 #
elixir
iex(1)> %{key => value} = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(2)> key
:age
iex(3)> value
30
4.5 混合匹配 #
elixir
iex(1)> %{name: name, rest} = %{name: "Alice", age: 30, city: "NYC"}
%{age: 30, city: "NYC", name: "Alice"}
iex(2)> name
"Alice"
iex(3)> rest
%{age: 30, city: "NYC"}
五、二进制匹配 #
5.1 基本匹配 #
elixir
iex(1)> <<a, b, c>> = <<1, 2, 3>>
<<1, 2, 3>>
iex(2)> a
1
iex(3)> b
2
iex(4)> c
3
5.2 指定位数 #
elixir
iex(1)> <<a::size(8), b::size(8)>> = <<255, 128>>
<<255, 128>>
iex(2)> a
255
iex(3)> b
128
5.3 字符串头部匹配 #
elixir
iex(1)> <<first::utf8, rest::binary>> = "Hello"
"Hello"
iex(2)> first
72
iex(3)> rest
"ello"
iex(4)> <<first::utf8, _rest::binary>> = "你好"
"你好"
iex(5)> first
20320
5.4 解析二进制数据 #
elixir
defmodule BinaryParser do
def parse_header(<<
magic::binary-size(4),
version::size(32),
flags::size(32),
rest::binary
>>) do
%{
magic: magic,
version: version,
flags: flags,
data: rest
}
end
end
六、Pin操作符 #
6.1 基本用法 #
使用 ^ 钉住变量,进行值比较而非重新绑定:
elixir
iex(1)> x = 1
1
iex(2)> ^x = 1
1
iex(3)> ^x = 2
** (MatchError) no match of right hand side value: 2
6.2 在模式中使用 #
elixir
iex(1)> expected = 1
1
iex(2)> {^expected, result} = {1, "Success"}
{1, "Success"}
iex(3)> result
"Success"
iex(4)> {^expected, result} = {2, "Success"}
** (MatchError) no match of right hand side value: {2, "Success"}
6.3 在函数参数中使用 #
elixir
defmodule Example do
def greet(%{name: name, language: "elixir"}) do
"Welcome to Elixir, #{name}!"
end
def greet(%{name: name, language: "erlang"}) do
"Welcome to Erlang, #{name}!"
end
def greet(%{name: name}) do
"Hello, #{name}!"
end
end
6.4 在映射键中使用 #
elixir
iex(1)> key = :name
:name
iex(2)> %{^key => value} = %{name: "Alice", age: 30}
%{age: 30, name: "Alice"}
iex(3)> value
"Alice"
七、函数中的模式匹配 #
7.1 多子句函数 #
elixir
defmodule Math do
def zero?(0), do: true
def zero?(_), do: false
def sign(n) when n > 0, do: 1
def sign(n) when n < 0, do: -1
def sign(0), do: 0
end
7.2 参数解构 #
elixir
defmodule User do
def full_name(%{first: first, last: last}) do
"#{first} #{last}"
end
def greet(%{name: name, age: age}) when age >= 18 do
"Hello, #{name}!"
end
def greet(%{name: name}) do
"Hi, #{name}!"
end
end
7.3 递归函数 #
elixir
defmodule Recursion do
def factorial(0), do: 1
def factorial(n) when n > 0, do: n * factorial(n - 1)
def fib(0), do: 0
def fib(1), do: 1
def fib(n) when n > 1, do: fib(n - 1) + fib(n - 2)
def reverse([]), do: []
def reverse([head | tail]), do: reverse(tail) ++ [head]
end
八、case表达式 #
8.1 基本语法 #
elixir
iex(1)> case {1, 2, 3} do
...> {1, x, 3} -> "Matched with x = #{x}"
...> {4, 5, 6} -> "Won't match"
...> _ -> "Match anything"
...> end
"Matched with x = 2"
8.2 守卫子句 #
elixir
iex(1)> case {1, 2, 3} do
...> {1, x, 3} when x > 0 -> "x is positive"
...> {1, x, 3} when x < 0 -> "x is negative"
...> _ -> "No match"
...> end
"x is positive"
8.3 处理结果 #
elixir
def handle_response(response) do
case response do
{:ok, data} ->
process_data(data)
{:error, :not_found} ->
{:error, "Resource not found"}
{:error, reason} ->
{:error, reason}
end
end
九、with表达式 #
9.1 基本语法 #
with 用于链式匹配,任一匹配失败则提前退出:
elixir
iex(1)> with {:ok, a} <- {:ok, 1},
...> {:ok, b} <- {:ok, 2},
...> {:ok, c} <- {:ok, 3} do
...> a + b + c
...> end
6
9.2 处理错误 #
elixir
def fetch_user(id) do
with {:ok, user} <- Repo.get(User, id),
{:ok, posts} <- Repo.get_posts(user),
{:ok, comments} <- Repo.get_comments(posts) do
{:ok, %{user: user, posts: posts, comments: comments}}
end
end
9.3 else子句 #
elixir
def create_user(params) do
with {:ok, user} <- validate_params(params),
{:ok, user} <- insert_user(user),
{:ok, token} <- generate_token(user) do
{:ok, %{user: user, token: token}}
else
{:error, :invalid_params} ->
{:error, "Invalid parameters"}
{:error, :duplicate_email} ->
{:error, "Email already exists"}
{:error, reason} ->
{:error, reason}
end
end
十、总结 #
本章学习了:
| 模式 | 示例 | 说明 |
|---|---|---|
| 元组匹配 | {a, b} = {1, 2} |
解构元组 |
| 列表匹配 | [head | tail] = [1, 2, 3] |
头尾分解 |
| 映射匹配 | %{name: name} = user |
提取键值 |
| 二进制匹配 | <<a, b>> = <<1, 2>> |
解析二进制 |
| Pin操作符 | ^x = 1 |
值比较 |
| case表达式 | case x do ... end |
多分支匹配 |
| with表达式 | with {:ok, x} <- f() do ... end |
链式匹配 |
准备好学习集合类型了吗?让我们进入下一章。
最后更新:2026-03-27