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