Elixir 中如何使用管道语法重构代码并访问中间结果?
Elixir管道语法优化实现
Elixir管道|>的核心运作规则非常明确:将上一个表达式的输出结果,自动作为下一个被调用函数的第一个位置参数传入。多数人管道语法写不通,本质是没遵守这个传参规则,或是把存在多依赖的计算硬拆成割裂的链式调用。
优化后的可运行代码
def show(conn, %{"id" => id}) do project = id |> Clients.get_project!() |> then(fn proj -> total_budget = total_budget(proj.budget_items) used_budget = budget_used(proj.work_items) %{proj | budget: total_budget, budget_used: used_budget, budget_remaining: total_budget - used_budget } end) changeset = %BudgetItem{project_id: project.id} |> Clients.change_budget_item() render(conn, "show.html", project: project, changeset: changeset) end
写法说明
- 没有沿用原本三次独立
Map.put_new的拆分逻辑,而是在单个then/2块中,一次性接住上游传入的初始project结构,集中完成三个关联值的计算,一次性更新struct字段,减少重复的结构取值操作。因为示例中补充的budget、budget_used、budget_remaining都是计算出来的虚拟字段,原本不存在于Project struct中,因此使用struct语法更新和原本的Map.put_new行为完全一致,不存在覆盖已有字段的问题。 then/2是适配管道的灵活工具:它可以完整接住上游的传值,不受管道自动插第一参数的规则限制,适合处理存在多字段依赖的计算场景。- 若使用Elixir 1.15及以上版本,可通过桩语法简化逐字段补充的写法,和原本的代码逻辑完全对齐:
project = id |> Clients.get_project!() |> Map.put_new(:budget, total_budget(.budget_items)) |> Map.put_new(:budget_used, budget_used(.work_items)) |> Map.put_new(:budget_remaining, .budget - .budget_used)
常见踩坑点
- 不要把多依赖的计算硬拆成无关联的链式步骤:比如直接把
.budget - .budget_used作为独立管道步骤传参,此时管道中的project还未注入刚计算的budget、budget_used字段,会拿到nil导致计算错误。 - 不要手动错误排列函数参数:比如写
Map.put_new(:budget, value, project),管道会自动把上游的project插到第一个参数位置,实际执行会变成Map.put_new(project, :budget, value),额外手动传参会直接触发函数匹配错误。
内容的提问来源于stack exchange,提问作者tomr
相关产品推荐
相关产品推荐

