Подтвердить что ты не робот

Erlang style - case vs function pattern matching

У меня есть сцена, на которой я написал довольно много кода Erlang, и я вижу, что какой-то стиль (плохой или хороший) ползет к тому, как я его писал. Эта конкретная идиома, на которую мне хотелось бы высказать мнение, - лучше ли (более читабельно/быстрее/безотносительно) преобразовывать операторы стиля case в соответствие шаблону функции?

например.

Сравнить (надуманный пример)

case {Size > 100000, Type} of
    {true, ets } ->
         %% Do something to convert to dets
         something;
    {false, dets} ->
         %% do something to convert to ets
         somethingelse;
    _ ->
         ignoreit
end;

с

...
maybeChangeStorage(Size, Type)
...

maybeChangeStorage(Size, ets) when Size > 10000 ->
   something;
maybeChangeStorage(Size, dets) when Size < 10000 ->
   somethingelse;
maybeChangeStorage(_,_) ->
   ignoreit.

Я предпочитаю последнее в большинстве случаев, но меня бы интересовало другое мнение.

4b9b3361

Ответ 1

Второй предпочтительный вариант, особенно если вы можете оставить предложения в одной строке:

maybeCngStor(Sz, ets)  when Sz > 10000 -> something;
maybeCngStor(Sz, dets) when Sz < 10000 -> somethingelse;
maybeCngStor(_,_)                      -> ignoreit.

Делает это очень легко читать и рассуждать. Всегда выбирайте стиль, который будет легче всего читать в будущем. Часто вы найдете набор предложений, в которых один из 10 лайнеров, а остальные - только одна строка - вывести длинную функцию:

maybeCngStor(Sz, ets)  when Sz > 10000 -> something;
maybeCngStor(Sz, dets) when Sz < 10000 -> somethingelse();
maybeCngStor(_,_)                      -> ignoreit.

somethingelse() ->
   (...)
   Return.

Маленькие вещи, такие как выкладка предложений, чтобы выровнять их и использовать короткие переменные имена, - но не попадают в ловушку, чтобы все изменить на P, Q, R.

Хороший трюк, если вы используете записи, много, чтобы сопоставить записи с короткими переменными:

#record{foo = F, bar = B, baz = Bz} = Parameter

Это дает вам короткие имена переменных, которые имеют смысл, когда вы парашютируете в функцию от 10 000 футов, ища ошибку в следующее Рождество. F, очевидно, является Foo и т.д. И т.д.

Ответ 2

Вы можете сделать эти примеры более похожими:

case Type of
   ets  when Size > 10000 -> ...;
   dets when Size < 10000 -> ...;
   _ -> ...
end.

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

Одна вещь, заслуживающая рассмотрения, - это то, что в случае ошибки функция записывает аргументы типа, отличные от ets/dets. Если это действительно не то, что вы хотите, стоит сделать этот пункт более ограничительным.

Ответ 3

Узнайте, что у вас есть Erlang для отличного использования имеет небольшой раздел когда выбрать case и когда использовать function. Две вещи упоминаются:

  • Они представлены одинаковыми в VM, поэтому нет никакой разницы в производительности между двумя решениями.

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

В целом, это, вероятно, просто вопрос стиля и вкуса.

Ответ 4

Как для меня первый стиль более ясен и может быть быстрее. Но для этого нужно протестировать. Во втором случае, если type!= Ets, тогда будут оцениваться как "Размеp > 10000", так и "Размер < 10000".

Ответ 5

(Поставьте в качестве ответа, чтобы получить форматирование кода...!)

Одна вещь, которую я обнаружил, когда я делал некоторые изменения, что этот подход может изменить короткое замыкание по умолчанию. Например.

case A > 10 of 
      true -> 
             case B > 10 of 
                  true -> dummy1; 
                  false -> dummy2 
             end; 
      false -> dummy3 
end 

должен всегда выполнять B > 10, если вы назвали его как

doTest(A > 10, B > 10) 

когда

doTest(true, true) -> dummy1; 
doTest(true, false) -> dummy2; 
doTest(false, _) -> dummy3. 

который иногда не то, что вы хотите!

Ответ 6

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