Как провести рефакторинг кейсов с чрезмерным вложением - PullRequest
0 голосов
/ 14 января 2019

Во многих ситуациях мне нужно сопоставить шаблон как с самой структурой, так и с ее полями, и приступить к выполнению некоторых дальнейших действий, когда некоторые промежуточные результаты не пусты.

Однако сама структура может быть 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. Мой фактический вариант использования шире, чем предполагал мой первоначальный вопрос, поэтому я обновил вопрос.)

Оригинальный код, к которому применяются ответы Алексея Матюшкина и Шехаряра:

experiment = Repo.get(Experiment, experiment_id)

case experiment do
  nil ->
    :error

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

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Я бы пошел с прямым совпадением паттернов.

Experiment
|> Repo.get(experiment_id)
|> case do
  %Experiment{active: true, other_attribute: :value} ->
    # do stuff
  _ ->
    :error
end
0 голосов
/ 05 февраля 2019

Другой способ - использовать синтаксис 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
0 голосов
/ 14 января 2019

Как насчет оператора короткого замыкания &&?

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
...