问题描述
考虑以下代码:
with {:a,first_result} <- {:a,List.first(["apple"])},{:b,b} <- {:b,%{} |> to_string} do
{:ok,"happy path"}
else
{:a,_} -> {:error,"this will never be a problem"}
{:b,error} -> {:error,"Why can I not print #{first_result} here?"}
end
我通过反复试验得知,此代码将不返回
{:error,"Why can I not print apple here?"}
正如我最初对这种语法所期望的那样。相反,编译器告诉我first_result
块中未定义else
。这是有道理的,因为“子句链”返回失败子句的错误结果。
所以我有2个问题:
- 达到预期结果的最佳方法是什么?我应该只使用两个单独的
case
表达式吗? - 想象一下,如果第一子句使用
Repo.insert
向数据库添加了一些内容。 Ecto是否知道它在with
表达式中并在提交事务之前等待所有子句成功执行? :thinking:这似乎不太可能。那么,为什么这个表达式不允许我们访问任何成功的结果?
在使用with
时似乎应该非常小心,因为如果我理解正确(我可能不太理解),那么我将获得“部分成功”,而看不到成功的结果。
欢迎任何建议和见识!我希望问题清楚。
P.S。我已经读过https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1。它只是说“链条被终止”。
解决方法
我在这里回答了我的问题:
向Bluejay用户提供道具。
用他们的话说,“这有效”:
with {:a,first_result} <- {:a,List.first(["apple"])},{:b,first_result,:something} <- {:b,:other_thing} do
{:ok,"happy path"}
else
{:a,_} -> {:error,"this will never be a problem"}
{:b,"Now I can print #{first_result} here"}
end
所以答案是使用先前子句结果中的变量来扩展要匹配的子句元组。