如何优雅地检查Erlang中的许多条件?

如何优雅地检查Erlang中的许多条件?,erlang,Erlang,因此,当用户发送注册帐户的请求时,他们会发送用户名、密码、电子邮件和其他信息。注册功能必须验证其所有数据。例如: 验证未使用的电子邮件 验证未使用的用户名 验证用户名是否为字母数字 验证所有字段的长度是否超过X个字符 验证所有字段的长度是否小于Y个字符 现在我不想有一个5级的if或case语句,但我还有什么其他选择呢?将其拆分为单独的函数听起来是个好主意,但接下来我只需要在某种条件下检查函数的返回值,这又回到了最初的问题 我可以将它们分成函数,然后调用一个if语句,将所有的条件或d一起调用,

因此,当用户发送注册帐户的请求时,他们会发送用户名、密码、电子邮件和其他信息。注册功能必须验证其所有数据。例如:

  • 验证未使用的电子邮件
  • 验证未使用的用户名
  • 验证用户名是否为字母数字
  • 验证所有字段的长度是否超过X个字符
  • 验证所有字段的长度是否小于Y个字符
现在我不想有一个5级的if或case语句,但我还有什么其他选择呢?将其拆分为单独的函数听起来是个好主意,但接下来我只需要在某种条件下检查函数的返回值,这又回到了最初的问题

我可以将它们分成函数,然后调用一个if语句,将所有的条件或d一起调用,但这并不能满足我的要求,因为我需要能够告诉用户如果存在特定错误

在erlang如何处理这种情况?是否存在与return语句等价的语句,或者它必须是函数中最后一个可执行的行才能作为返回值

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.