如何通过过多的嵌套重构案例语句

时间:2019-01-13 21:27:40

标签: functional-programming pattern-matching elixir phoenix-framework

在许多情况下,我发现自己需要对结构本身及其字段进行模式匹配,并在某些中间结果不为空时继续执行一些进一步的操作。

但是,结构本身可能首先是nil。这导致我编写了多个嵌套匹配,例如

experiment = Repo.get(Experiment, experiment_id)

case experiment do
  nil ->
    # Error 1

  _ ->
    case experiment.active do
      false -> # Error 2
      true -> 
        case Repo.all(assoc(experiment, :experiment_results)) do
          [] -> # Error 3
          results -> # Do stuffs
    end
end

理想情况下,我想编写没有太多嵌套的代码。

如何重构代码?


(请注意,我最初的问题是关于结构上可能为nil的模式匹配。我的实际用例比我最初提出的问题要广,因此我更新了该问题。)

AlekseiMatiushkin和Sheharyar的答案所适用的原始代码:

experiment = Repo.get(Experiment, experiment_id)

case experiment do
  nil ->
    :error

  _ ->
    case experiment.active do
      false -> :error
      true -> # Do stuffs
    end
end

3 个答案:

答案 0 :(得分:5)

我会直接进行图案匹配。

Experiment
|> Repo.get(experiment_id)
|> case do
  %Experiment{active: true, other_attribute: :value} ->
    # do stuff
  _ ->
    :error
end

答案 1 :(得分:1)

&&短路操作员如何?

if experiment && experiment.active && experiment.other do
  # do something
else
  :error
end

您还可以使用cond添加更多案例:

cond do
  experiment && experiment.active && experiment.other ->
    # do something

  !experiment.active ->
    {:error, :inactive}

  is_nil(experiment) ->
    {:error, :experiment_is_nil}

  true ->
    {:error, :unknown}
end

答案 2 :(得分:0)

另一种方法是使用with语法。它从根本上规定了“快乐路径”应该是什么,即使该路径需要进行多个相对复杂的检查:

with experiment <- Repo.get(Experiment, id),
     {:nil_experiment, false} <- {:nil_experiment, is_nil(experiment)},
     experiment_results <- Repo.all(assoc(experiment, :experiment_results)),
     {:empty_results, false} <- {:empty_results, Enum.empty?(experiment_results)} do
do
  # Do stuffs with `experiment_results`
else
  {:nil_experiment, true} ->
     # Error message 1

  {:empty_results, true} ->
     # Error message 2

  _ ->
     # Unknown error
end