因此,当用户发送注册帐户的请求时,他们会发送用户名,密码,电子邮件和其他信息。注册功能必须验证其所有数据。一个例子是:
现在我不想要5级深度if或case语句,但我还有其他选择吗?将它拆分成单独的函数听起来是个好主意,但是我只需要在某种条件下检查函数的返回值,它就会回到原来的问题。
我可以将它们分成函数,然后调用一个if语句,并将所有条件OR一起调用,但这不会给我我想要的东西,因为我需要能够告诉用户具体的错误,如果有的话是一个。
如何在erlang中处理这种情况?是否有一个等价的return语句,或者它必须是函数中作为返回值的最后一个可执行行?
答案 0 :(得分:32)
Joe Armstrong的建议之一:程序成功案例代码与错误处理分开。你可以这样做
create_user(Email, UserName, Password) ->
try
ok = new_email(Email),
ok = valid_user_name(UserName),
ok = new_user(UserName),
ok = strong_password(Password),
...
_create_user(Email, UserName, Password)
catch
error:{badmatch, email_in_use} -> do_something();
error:{badmatch, invalid_user_name} -> do_something();
error:{badmatch, user_exists} -> do_something();
error:{badmatch, weak_password} -> do_something();
...
end.
请注意,您可以更好地执行create_user函数中的所有错误捕获。
create_user(Email, UserName, Password) ->
ok = new_email(Email),
ok = valid_user_name(UserName),
ok = new_user(UserName),
ok = strong_password(Password),
...
_create_user(Email, UserName, Password).
main() ->
try
...
some_function_where_create_user_is_called(),
...
catch
...
error:{badmatch, email_in_use} -> do_something();
error:{badmatch, invalid_user_name} -> do_something();
error:{badmatch, user_exists} -> do_something();
error:{badmatch, weak_password} -> do_something();
...
end.
模式匹配是Erlang中最酷的事情之一。请注意,您可以将标记与badmatch错误相关联
{my_tag, ok} = {my_tag, my_call(X)}
和自定义数据
{my_tag, ok, X} = {my_tag, my_call(X), X}
如果异常足够快,则取决于您的期望。我的2.2GHz Core2 Duo英特尔的速度: 一秒钟内大约有2百万个例外(0.47us),而成功(外部)函数调用达到6百万(0.146us) - 可以猜测异常处理需要大约0.32us。 在本机代码中,它是6.8对47每秒,处理大约需要0.125us。 try-catch构造可能会有一些额外的成本,在本机代码和字节代码中成功函数调用大约是5-10%。
答案 1 :(得分:4)
User = get_user(),
Check_email=fun(User) -> not is_valid_email(User#user.email) end,
Check_username=fun(User) -> is_invalid_username(User#user.name) end,
case lists:any(fun(Checking_function) -> Checking_function(User) end,
[Check_email, Check_username, ... ]) of
true -> % we have problem in some field
do_panic();
false -> % every check was fine
do_action()
end
所以它不再是5级了。对于真正的程序,我猜你应该使用list:foldl来累积每个检查功能的错误信息。因为现在简单地说“一切都很好”或“有些问题”。
请注意,通过这种方式添加或删除检查条件并不是什么大问题
对于“是否存在等效的返回语句......” - 请查看try catch throw语句,在这种情况下抛出类似return的行为。
答案 2 :(得分:0)
以@JLarky的答案为基础,这是我想到的。它还从Haskell的单子中汲取了一些灵感。
-record(user,
{name :: binary(),
email :: binary(),
password :: binary()}
).
-type user() :: #user{}.
-type bind_res() :: {ok, term()} | {error, term()} | term().
-type bind_fun() :: fun((term()) -> bind_res()).
-spec validate(term(), [bind_fun()]) -> bind_res().
validate(Init, Functions) ->
lists:foldl(fun '|>'/2, Init, Functions).
-spec '|>'(bind_fun(), bind_res())-> bind_res().
'|>'(F, {ok, Result}) -> F(Result);
'|>'(F, {error, What} = Error) -> Error;
'|>'(F, Result) -> F(Result).
-spec validate_email(user()) -> {ok, user()} | {error, term()}.
validate_email(#user{email = Email}) ->
...
-spec validate_username(user()) -> {ok, user()} | {error, term()}.
validate_username(#user{name = Name}) ->
...
-spec validate_password(user()) -> {ok, user()} | {error, term()}.
validate_password(#user{password = Password}) ->
...
validate(#user{...}, [
fun validate_email/1,
fun validate_username/1,
fun validate_password/1
]).
答案 3 :(得分:-3)
也许你需要使用
receive
message1 -> code1;
message2 -> code2;
...
end.
但是,当然会有spawn()方法。