关于 elixir-idioms
elixir-idioms 是编写符合 Elixir 惯用法代码的参考技能,强调适用于 BEAM 的模式。它通过规则、决策指南和示例讲解控制流、错误处理、进程与 OTP。
主要功能
- 01运用模式匹配与管道操作符
- 02选择错误处理约定
- 03挑选进程和 OTP 组件
- 04规避常见 Elixir 陷阱
- 05查阅主题明确的参考指南
适用场景
- 01检查 Elixir 代码是否符合惯用模式
- 02在函数、Agent、GenServer 和 Task 间选择
- 03处理预期与意外错误
- 04设计受监督的长生命周期进程
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ oliver-kriska/ claude-elixir-phoenix --skill elixir-idioms安装后在 Claude Code 中输入/elixir-idioms确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/anti-patterns.mdelixir-118-features.mdelixir-120-type-system.mderror-handling.mdmix-tasks.mdotp-patterns.mdpattern-matching.mdtroubleshooting.mdwith-and-pipes.md详细介绍
Elixir 惯用法
编写符合 Elixir 惯用风格代码的参考指南,采用适配 BEAM 的模式。
铁律——绝不违反
- 没有运行时理由就不要创建进程——进程用于建模并发、状态和隔离,而不是代码结构
- 消息会被复制(64 字节以上的二进制数据除外)——保持消息精简
- 守卫中使用
and/or/not——守卫中绝不使用短路运算符(守卫要求操作数为布尔值) - 外部数据使用变更集——用户输入使用
cast/4,内部数据使用change/2 - 仅对外部代码使用 rescue——绝不使用 rescue 控制流程
- 不要动态创建原子——
String.to_atom(user_input)会导致内存泄漏(原子不会被垃圾回收) - 编译时读取的文件使用 @external_resource——在编译时读取文件的模块必须声明
@external_resource - 监督所有长生命周期进程——生产环境中绝不直接调用
GenServer.start_link/Agent.start_link。使用监督树 - 封装第三方库 API——始终通过项目自有模块门面封装外部依赖。这样无需修改调用方即可替换依赖
- Mix 任务只启动所需内容——使用
Mix.Task.run("app.config")+Application.ensure_all_started/1,绝不使用Mix.Task.run("app.start")(它会启动完整的树:端点端口、Oban 消费任务) - 启动进程前捕获区域设置——Gettext/CLDR 的区域设置是进程本地的。在调用方读取并显式传递;新启动的 Task/GenServer 会使用默认区域设置
BEAM 架构(Elixir 采用此设计的原因)
- 进程开销低(2.6KB)——可大量创建进程以实现并发/隔离
- 完全的内存隔离——没有共享状态,无需锁
- 消息会被复制(64 字节以上的二进制数据除外)——保持消息精简
- 每进程垃圾回收——不会发生全局垃圾回收暂停
- “让它崩溃”——监督者会将其重启到已知的良好状态
核心原则
- 优先使用模式匹配,而非条件判断——先用函数头,再用
case,最后用cond - 预期失败使用带标签的元组——预期错误使用
{:ok, _}/{:error, _},程序错误则抛出异常 - 使用管道运算符转换数据——从数据开始,绝不对单次调用使用管道
- 让它崩溃——处理预期错误,遇到意外错误则崩溃
- 明确胜于隐式——清楚表达意图
快速决策树
控制流程
Need patterns? → case (or function heads)
Multiple operations? → with
Boolean conditions? → cond (multiple) or if (single)
错误处理
Expected failure? → {:ok, _}/{:error, _} tuples
Unexpected/bug? → raise exception (let supervisor handle)
External library? → rescue (only here!)
OTP
Need state?
├─ No → Plain functions
├─ Simple get/update → Agent or ETS
├─ Complex messages/timeouts → GenServer
└─ One-off async → Task
快速模式
# Pattern match in function head
def process(%{status: :active} = user), do: activate(user)
def process(%{status: :inactive} = user), do: deactivate(user)
# with for happy path
with {:ok, user} <- get_user(id),
{:ok, order} <- create_order(user) do
{:ok, order}
end
# Task for async
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(除非使用 1.18 中已弃用的 unless) |
参考资料
如需了解详细模式,请参阅:
${CLAUDE_SKILL_DIR}/references/pattern-matching.md- 模式匹配、守卫、二进制匹配${CLAUDE_SKILL_DIR}/references/otp-patterns.md- GenServer、Supervisor、Task、Registry${CLAUDE_SKILL_DIR}/references/error-handling.md- 带标签的元组、rescue、with${CLAUDE_SKILL_DIR}/references/with-and-pipes.md- 何时使用with和|>(惯用模式)${CLAUDE_SKILL_DIR}/references/troubleshooting.md- 生产环境 BEAM 调试(内存、性能、崩溃)${CLAUDE_SKILL_DIR}/references/anti-patterns.md- 常见错误及修正方法${CLAUDE_SKILL_DIR}/references/mix-tasks.md- Mix 任务命名、选项解析、Shell 输出${CLAUDE_SKILL_DIR}/references/elixir-118-features.md- Duration 模块、dbg 改进(1.18+)${CLAUDE_SKILL_DIR}/references/elixir-120-type-system.md- 渐进式类型检查器、dynamic()、将已验证的错误作为编译警告(1.20+、OTP 27+)
评论
支持 Markdown