2009-03-20 8 views
13

Por lo tanto, cuando un usuario envía una solicitud para registrar una cuenta, envía su nombre de usuario, contraseña, correo electrónico y otra información. La función de registro debe verificar todos sus datos. Ejemplo sería:¿Cómo verifico elegantemente muchas condiciones en Erlang?

  • verificar correo electrónico no esté en uso
  • verificar nombre de usuario no está en uso
  • verificar nombre de usuario es alfanumérica
  • verificar todos los campos están por encima de X caracteres largos
  • verificar todos los campos son menos de Y caracteres largos

Ahora no quiero tener un nivel profundo de 5 niveles si, pero ¿qué otras opciones tengo? Dividirlo en funciones separadas suena como una buena idea, pero luego solo tengo que verificar el valor de retorno de las funciones en algún tipo de condicional y volver al problema original.

Podría separarlos en funciones y luego llamar a una declaración if con todas las condicionales O juntas, pero eso no me daría lo que quiero porque tengo que poder decirle al usuario el error específico si había uno.

¿Cómo se maneja este tipo de situación en erlang? ¿Hay un equivalente de una declaración de retorno, o tiene que ser la última línea ejecutable en una función para ser un valor de retorno?

+0

Una publicación cruzada con la lista de correo de Erlang - ahora hay un número considerable de publicaciones cruzadas ... –

Respuesta

32

Una de las sugerencias de Joe Armstrong: código de caso de éxito del programa separado del manejo de errores. Se puede hacer de esta manera

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. 

nota que usted puede hacer todos los errores de captura de la función create_user que es mejor.

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. 

Coincidencia de modelo es una de las mejores cosas en Erlang. Tenga en cuenta que puede implicar su etiqueta a BadMatch error

{my_tag, ok} = {my_tag, my_call(X)} 

y personalizados de datos demasiado

{my_tag, ok, X} = {my_tag, my_call(X), X} 

Si excepción es lo suficientemente rápido para usted depende de sus expectativas. Velocidad en mi Core2 Duo de 2.2GHz Intel: alrededor de 2 millones de excepciones en un segundo (0.47us) en comparación con 6 millones de llamadas de función exitosa (externa) (0.146us) - uno puede adivinar que el manejo de excepciones toma alrededor de 0.32us. En el código nativo es 6.8 vs 47 millones por segundo y el manejo puede tomar alrededor de 0.125us. Puede haber un costo adicional para la construcción try-catch, que es aproximadamente del 5-10% para la llamada a función de éxito tanto en código nativo como en byte.

+2

+1 por la respuesta: en ambos libros erlang no es "explícito que puedes poner más de una expresión en try/catch. Ty por la información! – scooterman

+0

¿requiere esto que las funciones como 'new_email' arrojen un tipo específico de error como' email_in_use'? – Tommy

+0

@Tommy: No, solo devuelve: 'try ok = (fun() -> email_in_use end)() catch error: {badmatch, email_in_use} -> io: format (" OK! ~ N ", []) end. ' –

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 

Así que ya no tiene 5 niveles de profundidad. Para el programa real supongo que debe usar listas: foldl para acumular el mensaje de error de cada función de comprobación. Porque por ahora, lo simple dice 'todo bien' o 'algún problema'.

Tenga en cuenta que de esta manera agregar o quitar condición de cheques no es un gran problema

Y para "¿Hay un equivalente de una sentencia return ..." - mira intento sentencia catch tiro, tirar actúa como regresar en este caso.

-3

Tal vez tendrá que usar de

receive 
    message1 -> code1; 
    message2 -> code2; 
    ... 
end. 

Pero, por supuesto, habrá desovar) (métodos.

Cuestiones relacionadas