Elixir元组 #
一、元组基础 #
1.1 元组定义 #
元组是固定大小的有序集合,使用花括号定义:
elixir
iex(1)> {1, 2, 3}
{1, 2, 3}
iex(2)> {:ok, "Success"}
{:ok, "Success"}
iex(3)> {:error, :not_found}
{:error, :not_found}
iex(4)> {1, "two", :three}
{1, "two", :three}
1.2 元组特性 #
- 固定大小,创建后不能改变
- 内存连续存储
- 随机访问O(1)
- 适合存储少量固定元素
elixir
iex(1)> tuple = {1, 2, 3}
{1, 2, 3}
iex(2)> tuple_size(tuple)
3
iex(3)> elem(tuple, 0)
1
iex(4)> elem(tuple, 2)
3
1.3 元组与列表的区别 #
| 特性 | 元组 | 列表 |
|---|---|---|
| 大小 | 固定 | 可变 |
| 内存 | 连续 | 链式 |
| 随机访问 | O(1) | O(n) |
| 修改 | O(n) | 头部O(1) |
| 用途 | 固定结构 | 动态集合 |
二、元组操作 #
2.1 访问元素 #
elixir
iex(1)> tuple = {:ok, 42, "result"}
{:ok, 42, "result"}
iex(2)> elem(tuple, 0)
:ok
iex(3)> elem(tuple, 1)
42
iex(4)> elem(tuple, 2)
"result"
iex(5)> tuple_size(tuple)
3
2.2 修改元素 #
elixir
iex(1)> tuple = {1, 2, 3}
{1, 2, 3}
iex(2)> put_elem(tuple, 1, :two)
{1, :two, 3}
iex(3)> tuple
{1, 2, 3}
注意:元组是不可变的,put_elem 返回新元组。
2.3 追加元素 #
elixir
iex(1)> tuple = {1, 2, 3}
{1, 2, 3}
iex(2)> Tuple.append(tuple, 4)
{1, 2, 3, 4}
iex(3)> Tuple.insert_at(tuple, 1, :inserted)
{1, :inserted, 2, 3}
2.4 删除元素 #
elixir
iex(1)> tuple = {1, 2, 3}
{1, 2, 3}
iex(2)> Tuple.delete_at(tuple, 1)
{1, 3}
2.5 转换 #
elixir
iex(1)> Tuple.to_list({1, 2, 3})
[1, 2, 3]
iex(2)> List.to_tuple([1, 2, 3])
{1, 2, 3}
三、模式匹配 #
3.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
3.2 大小匹配 #
元组大小必须匹配:
elixir
iex(1)> {a, b} = {1, 2, 3}
** (MatchError) no match of right hand side value: {1, 2, 3}
iex(1)> {a, b, c} = {1, 2}
** (MatchError) no match of right hand side value: {1, 2}
3.3 忽略元素 #
elixir
iex(1)> {a, _, c} = {1, 2, 3}
{1, 2, 3}
iex(2)> a
1
iex(3)> c
3
3.4 嵌套匹配 #
elixir
iex(1)> {a, {b, c}} = {1, {2, 3}}
{1, {2, 3}}
iex(2)> a
1
iex(3)> b
2
iex(4)> c
3
3.5 值匹配 #
elixir
iex(1)> {:ok, result} = {:ok, "Success"}
{:ok, "Success"}
iex(2)> result
"Success"
iex(3)> {:ok, result} = {:error, "Failed"}
** (MatchError) no match of right hand side value: {:error, "Failed"}
四、常见使用模式 #
4.1 函数返回值 #
元组常用于函数返回值,表示成功或失败:
elixir
defmodule FileProcessor do
def read_file(path) do
case File.read(path) do
{:ok, content} -> {:ok, process(content)}
{:error, reason} -> {:error, reason}
end
end
defp process(content) do
content
|> String.split("\n")
|> Enum.map(&String.trim/1)
end
end
4.2 处理结果 #
elixir
def handle_result(result) do
case result do
{:ok, data} ->
IO.puts("Success: #{data}")
{:error, :not_found} ->
IO.puts("Not found")
{:error, reason} ->
IO.puts("Error: #{reason}")
end
end
4.3 多返回值 #
elixir
defmodule Math do
def divmod(a, b) do
{div(a, b), rem(a, b)}
end
end
{quotient, remainder} = Math.divmod(10, 3)
4.4 配置选项 #
elixir
defmodule Config do
def parse({:database, host, port}) do
%{host: host, port: port}
end
def parse({:cache, ttl}) do
%{ttl: ttl}
end
end
4.5 坐标表示 #
elixir
defmodule Point do
def distance({x1, y1}, {x2, y2}) do
:math.sqrt(:math.pow(x2 - x1, 2) + :math.pow(y2 - y1, 2))
end
def move({x, y}, {dx, dy}) do
{x + dx, y + dy}
end
end
五、两元素元组 #
5.1 键值对 #
两元素元组常用于表示键值对:
elixir
iex(1)> {:name, "Alice"}
{:name, "Alice"}
iex(2)> [{:a, 1}, {:b, 2}, {:c, 3}]
[a: 1, b: 2, c: 3]
5.2 构建映射 #
elixir
iex(1)> Enum.into([{:a, 1}, {:b, 2}], %{})
%{a: 1, b: 2}
5.3 关键字列表 #
关键字列表是两元素元组的列表:
elixir
iex(1)> [a: 1, b: 2]
[a: 1, b: 2]
iex(2)> [{:a, 1}, {:b, 2}]
[a: 1, b: 2]
六、元组标签 #
6.1 标签元组 #
第一个元素作为标签:
elixir
defmodule Shape do
def area({:rectangle, width, height}) do
width * height
end
def area({:circle, radius}) do
:math.pi() * radius * radius
end
def area({:triangle, base, height}) do
0.5 * base * height
end
end
6.2 使用示例 #
elixir
iex(1)> Shape.area({:rectangle, 5, 3})
15
iex(2)> Shape.area({:circle, 2})
12.566370614359172
iex(3)> Shape.area({:triangle, 4, 3})
6.0
七、记录 #
7.1 定义记录 #
记录是带命名元素的元组:
elixir
defmodule User do
require Record
Record.defrecord(:user, name: nil, age: 0, email: nil)
end
7.2 使用记录 #
elixir
iex(1)> require User
User
iex(2)> u = User.user(name: "Alice", age: 30)
{:user, "Alice", 30, nil}
iex(3)> User.user(u, :name)
"Alice"
iex(4)> User.user(u, :age)
30
八、性能考虑 #
8.1 元组优势 #
elixir
tuple = {1, 2, 3, 4, 5}
elem(tuple, 4)
8.2 元组劣势 #
elixir
tuple = {1, 2, 3, 4, 5}
put_elem(tuple, 2, :new)
8.3 选择建议 #
| 场景 | 推荐 |
|---|---|
| 固定大小数据 | 元组 |
| 动态大小数据 | 列表 |
| 命名字段 | 映射或结构体 |
| 函数返回值 | 标签元组 |
九、与Erlang互操作 #
9.1 Erlang记录 #
Erlang记录在Elixir中是元组:
elixir
iex(1)> :erlang.time()
{22, 15, 30}
iex(2)> :erlang.date()
{2024, 1, 15}
9.2 处理Erlang返回值 #
elixir
case :file.read_file("test.txt") do
{:ok, binary} -> process_binary(binary)
{:error, :enoent} -> {:error, "File not found"}
{:error, reason} -> {:error, reason}
end
十、总结 #
本章学习了:
| 操作 | 示例 |
|---|---|
| 创建 | {1, 2, 3} |
| 访问 | elem(tuple, 0) |
| 修改 | put_elem(tuple, 0, :new) |
| 大小 | tuple_size(tuple) |
| 转换 | Tuple.to_list/1 |
| 模式匹配 | {a, b, c} = tuple |
准备好学习映射了吗?让我们进入下一章。
最后更新:2026-03-27