Вы должны всегда измерять, чтобы найти такие вещи.
Ваш код также не делает то, что вы думаете.
-module(glurk).
-compile(export_all).
fn2() ->
try
{ok, Result} = fn1(),
%Do something with Result
ok
catch
throw:Term -> Term;
exit:Reason -> {exit, Reason};
error:Reason -> {error,{Reason,erlang:get_stacktrace()}}
end.
fn1() ->
{error, a}.
Попробуйте это:
c(glurk).
./glurk.erl:6: Warning: variable 'Result' is unused
{ok,glurk}
16> glurk:fn2().
{error,{{badmatch,{error,a}},
[{glurk,fn2,0},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}}
Это потому, что fn1 не вызвал исключение
он получил нормальное возвращаемое значение {error, a}, которое
не соответствует шаблону с {ok, Result}
Первая версия вашего кода работает с функцией, которая либо возвращает нормальное значение
или вызывает исключение - вы должны написать это так:
fn1(....) ->
...
%% success case
Val;
%% failure case
throw(...) | exit(...) | error(...)
Нельзя просто накачать одну и ту же функцию на fn1 и fn2.
Если бы у вас был случай, когда вызываемая функция должна была выйти из глубокой рекурсии
тогда первый метод будет более эффективным, чем второй - так как вы могли бы
немедленно выйдите из глубокой рекурсии, сказав throw (...).
Таким образом, ответ зависит от природы функции, которую вы вызываете.
Код всегда должен быть оптимизирован для красоты, а не эффективности - так как у вас есть
поддерживать вещи - тогда их следует оптимизировать только в редких случаях
где это не достаточно быстро. Что должно быть оптимизировано, должно быть идентифицировано
измеряя программу (вы всегда будете удивлены здесь: -)
Я бы написал
{ok,Result} = ...
На самом деле ваш первый код содержит более тонкую ошибку
fn2() ->
try
{ok, Result} = fn1(),
%Do something with Result
ok
catch
throw:Term -> Term;
exit:Reason -> {exit, Reason};
error:Reason -> {error,{Reason,erlang:get_stacktrace()}}
end.
Подумай об этом. Пойманные ошибки сами по себе не обрабатывают ошибку
они просто возвращают кортежи типа {выход, причина} или {ошибка, причина}, это означает, что
следующий уровень вверх (т.е. вызывающий fn2) также придется возиться с проверкой
возвращается ошибка - если это будет повторяться на всех уровнях, код будет беспорядочным.
Способ "erlang" состоит в том, чтобы сделать один пробный бросок вверху программы и просто завершить его
внезапно с выходом (почему), если возникает ошибка.
На самом деле часто вам даже не следует этого делать - вы должны связать свой процесс с другим процессом.
тогда нарушающий процесс умрет и «другие процессы исправят ошибку».
Исключение распространяется вверх по стеку вызовов и перелетает к связанным процессам.
для лечения. Таким образом, у нас есть два типа процессов - те, которые не имеют встроенной обработки ошибок
и процессы, которые только обрабатывают ошибки.