Elixir:如何避免深度嵌套的 case 语句?

标签 elixir

假设我有一个函数 main_function这取决于其他三个函数的结果,每个函数都可以返回 {:ok, result}{:error, error} .如何避免在 javascript 中感觉像回调 hell 的深度嵌套的 case 语句。

例子:

def func1(input) do
  case SOMECONDITION do
    {:ok, result} ->
      {:ok, result}
    {:error, error} ->
      {:error, error}
  end
end

def func2(input) do
  case SOMECONDITION do
    {:ok, result} ->
      {:ok, result}
    {:error, error} ->
      {:error, error}
  end
end

def func3(input) do
  case SOMECONDITION do
    {:ok, result} ->
      {:ok, result}
    {:error, error} ->
      {:error, error}
  end
end

def main_function(input) do
  case func1(input) do
    {:ok, result} ->
      case func2(result) do
        {:ok, result} ->
          case func3(result) do
            {:ok, result} ->
              {:ok, EXPECTED_OUTCOME}
            {:error, error} ->
              {:error, error}
          end
        {:error, error} ->
          {:error, error}
      end
      {:error, error} ->
        {:error, error}  
    end
  end
end

只是感觉不太对...

最佳答案

[编辑]:我为涵盖此概念的精彩演讲添加了一个便捷链接,以及下面 ElixirConf 2018 中更复杂需求的解决方案。

别担心 - Elixir 可以满足您的需求。你想要this special form : with/1with/1当且仅当它们与预期结果匹配时,才会继续执行函数。

你的主要功能基本上看起来像:

def main_function(input) do
  with {:ok, result_1} <- func1(input),
       {:ok, result_2} <- func2(result_1),
        ...,
  do: {:ok, EXPECTED_OUTCOME}
end

当它找不到匹配项时,说因为有一个像 {:error, _error} 这样的元组特殊形式将返回遇到的第一个错误并停止执行函数。

您还可以添加一个 else 条件。我使用这个的一个例子是,当用户可能期望一些需要完成很多功能的操作时,我想提醒他们同样的事情,不管它在哪里失败:
def main_function(input) do
  with {:ok, result_1} <- func1(input),
       {:ok, result_2} <- func2(result_1),
        ... do
    {:ok, EXPECTED_OUTCOME}
  else
    _error ->
      {:error, "Couldn't complete action"}
  end
end

其他资源:

这是 Credo 的作者关于这个概念的精彩演讲,由 ElixirConf 2018 提供:https://www.youtube.com/watch?v=ycpNi701aCs&t=473s

这是一篇关于 with/1 的精彩帖子: https://www.erlang-solutions.com/blog/exploring-with-the-elixir-special-form.html

关于Elixir:如何避免深度嵌套的 case 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50827551/

相关文章:

postgresql - Elixir 无法连接到 PostgreSQL

elixir - Rails 引擎就像 Phoenix

elixir - 如何用Elixir中的索引减少?

elixir - Ecto assoc_constraint 不起作用

elixir - 如何为 mix.exs 中定义的别名提供描述?

rabbitmq - 为什么 RabbitMQ 中的消息优先级不对我的消息进行排序?

elixir - `in` 运算符如何使用 map ?

elixir - 将 `sum` 结果转换为 Ecto 中的整数

npm - Phoenix 框架 - 在子目录中执行 NPM 脚本

elixir - 无法访问主 elixir 项目中的依赖项配置