如何优雅地检查Erlang中的许多条件?
因此,当用户发送注册帐户的请求时,他们会发送用户名、密码、电子邮件和其他信息。注册功能必须验证其所有数据。例如:如何优雅地检查Erlang中的许多条件?,erlang,Erlang,因此,当用户发送注册帐户的请求时,他们会发送用户名、密码、电子邮件和其他信息。注册功能必须验证其所有数据。例如: 验证未使用的电子邮件 验证未使用的用户名 验证用户名是否为字母数字 验证所有字段的长度是否超过X个字符 验证所有字段的长度是否小于Y个字符 现在我不想有一个5级的if或case语句,但我还有什么其他选择呢?将其拆分为单独的函数听起来是个好主意,但接下来我只需要在某种条件下检查函数的返回值,这又回到了最初的问题 我可以将它们分成函数,然后调用一个if语句,将所有的条件或d一起调用,
- 验证未使用的电子邮件
- 验证未使用的用户名
- 验证用户名是否为字母数字
- 验证所有字段的长度是否超过X个字符
- 验证所有字段的长度是否小于Y个字符
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层深了。对于真正的程序,我想您应该使用lists:foldl来累积来自每个检查函数的错误消息。因为现在它简单地说“一切正常”或“有些问题”
请注意,以这种方式添加或删除检查条件并不是什么大问题
对于“是否存在与return语句等效的语句…”,请看try-catch-throw语句,在本例中,throw的行为类似于return。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 Intel上的速度:
与600万个成功(外部)函数调用(0.146us)相比,一秒钟内大约有200万个异常(0.47us)——可以猜测,异常处理大约需要0.32us。
在本机代码中,它是6.8 vs 4700万每秒,处理大约需要0.125us。try-catch构造可能会有一些额外的成本,这对于在本机代码和字节码中成功调用函数来说大约是5-10%。也许您需要使用
receive
message1 -> code1;
message2 -> code2;
...
end.
但是,当然会有spawn()方法。在@JLarky的答案的基础上,我想到了一些东西。它也从哈斯克尔的单子中得到了一些灵感
-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
]).
带有Erlang邮件列表的交叉帖子-现在有相当数量的交叉帖子了…+1的答案是:在两本Erlang书籍上,都没有明确表示可以在try/catch上放置多个表达式。我需要你的信息!这是否需要像
new\u-email
这样的函数来抛出一个特定类型的错误,比如email\u-in\u-use
?@Tommy:不,只需返回:try-ok=(fun()->email\u-in\u-use end)()捕获错误:{badmatch,email\u-in\u-use}->io:format(“ok!~n”,“[])end.