在许多情况下,我发现自己需要对结构本身及其字段进行模式匹配,并在某些中间结果不为空时继续执行一些进一步的操作。
但是,结构本身可能首先是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
答案 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