2009-03-20 6 views
13

Ainsi, lorsqu'un utilisateur envoie une demande d'enregistrement de compte, il envoie son nom d'utilisateur, son mot de passe, son adresse e-mail et d'autres informations. La fonction d'enregistrement doit vérifier toutes leurs données. Un exemple serait:Comment puis-je vérifier élégamment plusieurs conditions à Erlang?

  • vérifier email ne est pas utilisé
  • vérifier le nom d'utilisateur ne sont pas utilisés
  • vérifier le nom d'utilisateur est alphanumérique
  • vérifier tous les champs sont au-dessus de X caractères longs
  • vérifier tous les champs sont moins que les caractères Y longs

Maintenant, je ne veux pas avoir une instruction deep if 5 level, mais quelles autres options ai-je? Le découper en fonctions séparées sonne comme une bonne idée, mais ensuite je dois juste vérifier la valeur de retour des fonctions dans une sorte de conditionnel et c'est de retour au problème original.

Je pourrais les séparer en fonctions, puis appeler une instruction if avec toutes les conditions OR ensemble, mais cela ne me donnerait pas ce que je veux parce que je dois être en mesure de dire à l'utilisateur l'erreur spécifique si il y en avait un.

Comment gère-t-on ce genre de situation en erlang? Existe-t-il un équivalent d'une instruction return ou doit-il être la dernière ligne exécutable d'une fonction à être une valeur de retour?

+0

Un post croisé avec la liste de diffusion Erlang - il y a maintenant un bon nombre de messages croisés ... –

Répondre

32

Une des suggestions de Joe Armstrong: code de cas de réussite du programme séparé de la gestion des erreurs. Vous pouvez le faire de cette façon

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. 

Notez que vous pouvez faire toutes les erreurs captures de la fonction create_user qui est mieux.

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. 

La correspondance de formes est l'une des choses les plus cool d'Erlang. Notez que vous pouvez impliquer votre balise BadMatch erreur

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

et des données personnalisées trop

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

Si exception est assez rapide pour vous dépend de vos attentes. Vitesse sur mon Core2 Duo 2.2GHz Intel: environ 2 millions d'exceptions en une seconde (0.47us) par rapport à 6 millions d'appels de fonction de succès (externe) (0.146us) - on peut deviner que la gestion des exceptions prend environ 0,32us. En code natif, il est de 6,8 contre 47 millions par seconde et la manipulation peut prendre environ 0,125us. Il peut y avoir un coût supplémentaire pour la construction try-catch qui est d'environ 5-10% pour l'appel de fonction de succès à la fois natif et octet-code.

+2

+1 pour la réponse: Sur les deux livres erlang n'est pas 'explicite que vous pouvez mettre plus de une expression sur try/catch. Ty pour l'info! – scooterman

+0

cela nécessite-t-il les fonctions comme 'new_email' pour lancer un type spécifique d'erreur comme' email_in_use'? – Tommy

+0

@Tommy: Non, juste retour: 'try ok = (fun() -> email_in_use end)() erreur de capture: {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 

Il n'est donc plus à 5 niveaux de profondeur. Pour le vrai programme je suppose que vous devriez utiliser des listes: foldl pour accumuler un message d'erreur de chaque fonction de vérification. Parce que pour l'instant, il dit simplement «tout va bien» ou «un problème».

Notez que cette manière d'ajouter ou de supprimer le contrôle condition n'est pas une grosse affaire

Et pour « Y at-il un équivalent d'une déclaration de retour ... » - regardez essayer instruction throw catch, lancer des actes comme retourner dans ce cas.

-3

Peut-être que vous aurez besoin à l'aide de

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

Mais, bien sûr, il y aura des fraient() méthodes.

Questions connexes