Elixir最佳实践与模式Skill elixir-idioms

这个技能详细介绍了Elixir编程语言的惯用模式、BEAM架构原理、OTP框架应用和最佳实践。旨在帮助开发者编写高效、可维护的并发代码,适用于后端开发。关键词:Elixir,BEAM,OTP,函数式编程,并发编程,最佳实践。

后端开发 0 次安装 0 次浏览 更新于 3/11/2026

name: elixir-idioms description: Elixir 惯用模式、BEAM 架构、OTP 模式和最佳实践。在编写 Elixir 代码时加载,以确保符合惯用风格。 user-invocable: false

Elixir 惯用语

编写符合 BEAM 感知模式的惯用 Elixir 代码的参考。

铁律 — 永不违反这些

  1. 没有运行时原因,就不创建进程 — 进程建模并发、状态、隔离—而不是代码结构
  2. 消息会被复制 — 保持消息小(除了大于 64 字节的二进制数据)
  3. 守卫使用 and/or/not — 守卫中不要使用短路运算符(守卫需要布尔操作数)
  4. 外部数据使用变化集 — 用户输入使用 cast/4,内部使用 change/2
  5. 仅对外部代码使用 rescue — 永远不要用 rescue 进行控制流
  6. 不要动态创建原子String.to_atom(user_input) 会导致内存泄漏(原子不被垃圾回收)
  7. 编译时文件使用 @external_resource — 在编译时读取文件的模块必须声明 @external_resource
  8. 监督所有长期存活的进程 — 在生产中永远不要裸使用 GenServer.start_link/Agent.start_link。使用监督树
  9. 包装第三方库 API — 总是将外部依赖包装在项目拥有的模块后面。便于在不影响调用者的情况下替换

BEAM 架构(为什么 Elixir 这样工作)

  • 进程很便宜(2.6KB) — 为了并发/隔离,可以随意生成
  • 完全的内存隔离 — 没有共享状态,不需要锁
  • 消息会被复制(除了大于 64 字节的二进制数据) — 保持消息小
  • 每个进程的垃圾回收 — 没有全局 GC 暂停
  • “让它崩溃” — 监督器会重启到已知良好状态

核心原则

  1. 优先使用模式匹配而非条件判断 — 函数头优先,然后 case,然后 cond
  2. 标记元组用于预期失败{:ok, _}/{:error, _} 用于预期错误,raise 用于 bug
  3. 管道运算符用于数据转换 — 以数据开始,永远不要管道单个调用
  4. 让它崩溃 — 处理预期错误,对意外的崩溃
  5. 明确优于隐晦 — 明确表达意图

快速决策树

控制流

需要模式匹配? → case(或函数头)
多个操作? → with
布尔条件? → cond(多个)或 if(单个)

错误处理

预期失败? → {:ok, _}/{:error, _} 元组
意外/bug? → raise 异常(让监督器处理)
外部库? → rescue(仅此处!)

OTP

需要状态?
├─ 否 → 普通函数
├─ 简单获取/更新 → Agent 或 ETS
├─ 复杂消息/超时 → GenServer
└─ 一次性异步 → Task

快速模式

# 函数头中的模式匹配
def process(%{status: :active} = user), do: activate(user)
def process(%{status: :inactive} = user), do: deactivate(user)

# with 用于快乐路径
with {:ok, user} <- get_user(id),
     {:ok, order} <- create_order(user) do
  {:ok, order}
end

# Task 用于异步
Task.Supervisor.async_nolink(TaskSup, fn -> work() end)
|> Task.yield(5000) || Task.shutdown(task)

常见陷阱

错误 正确
length(list) == 0 list == []Enum.empty?(list)
list ++ [item] [item | list] |> Enum.reverse()
String.to_atom(input) String.to_existing_atom(input)
spawn(fn -> log(conn) end) ip = conn.ip; spawn(fn -> log(ip) end)
unless condition if !condition(unless 在 1.18 中已弃用)

参考文献

详细模式,参见:

  • references/pattern-matching.md - 模式匹配、守卫、二进制匹配
  • references/otp-patterns.md - GenServer、Supervisor、Task、Registry
  • references/error-handling.md - 标记元组、rescue、with
  • references/with-and-pipes.md - 何时使用 with|>(惯用模式)
  • references/troubleshooting.md - 生产 BEAM 调试(内存、性能、崩溃)
  • references/anti-patterns.md - 常见错误和修复
  • references/mix-tasks.md - Mix 任务命名、选项解析、shell 输出
  • references/elixir-118-features.md - Duration 模块、dbg 改进(1.18+)