2009-12-08 4 views
6

Ho una funzione in cui dispongo di una serie di dichiarazioni caso individuali.Erlang: ritorno da una funzione

case ... of 
    ... 
end, 

case ... of 
    ... 
end, 

... 

ecc

voglio tornare dalla funzione immediatamente quando si verifica una particolare condizione caso in una delle istruzioni case - in modo che il caso istruzione successiva non è selezionata, e la funzione appena uscite/ritorna. Come lo faccio?

risposta

13

Suggerisco di refactoring sfruttare tutta la potenza di Erlang e le sue abilità di abbinamento del modello.

Non esiste un operatore return. Inoltre, un fatto poco noto è che si può fare qualcosa di simile:

Return=case ... of

una dichiarazione case può avere un valore di "ritorno".

+1

Ecco perché si chiama espressione del caso. – Christian

+0

Sì, è qualcosa che vale la pena conoscere! Grazie. – jeffreyveon

+0

@jeffreyveon: la mia risposta soddisfa la tua domanda? – jldupont

4

Erlang non ha un operatore return. Dovrai rifattorizzare il tuo codice in funzioni più piccole.

Il codice originale ha due espressioni di caso concatenate con l'operatore virgola. Presumo che tu abbia alcuni effetti collaterali nell'espressione del primo caso che vuoi conservare. Qui di seguito, sto usando un immaginario return operatore:

case ... of 
    P1 -> return E1; 
    P2 -> E2; 
end, 

case ... of 
    ... 
end 

Un'espressione come questo può essere convertito in vero e proprio codice di Erlang con piccole funzioni e pattern matching con qualcosa di simile a questo:

case1(P1, ...) -> E1; 
case1(P2, ...) -> E2, case2(...). 
case2(...) -> ... 

Disclaimer: E ' Sono passati 10 anni da quando ho scritto il codice Erlang, quindi la mia sintassi potrebbe essere disattivata.

+0

Si prega di fornire un esempio di farlo. –

+0

Esempio aggiunto, spero che aiuti. –

2

In Erlang è sufficiente utilizzare la corrispondenza del modello per attivare la funzione appropriata. Se hai troppe clausole da coprire e trattare, ti suggerisco anche di rifattorizzare il codice un po '.

0

uso cattura/gettare

Il chiamante dice:

 
X = (catch foo(A, B)). 

poi scrivere

 
foo(A, B) -> 
    case ... of 
    ...throw(X) .. 
    end, 

    case ... of 
    ... throw (Y) 
    end, 
    ... 

Questo è generalmente considerato povero pratica di programmazione - dal momento che il programma ha più punti di uscita ed è difficile da tollerare

+2

Il lancio di Erlang è specifico per i ritorni non locali, non per la gestione degli errori - quindi in linea di principio questo è un approccio valido. In pratica, sospetto che il refactoring per evitarlo sarebbe meglio qui, ma senza vedere il codice è difficile sapere. – cthulahoops

+2

In linea di principio, potrebbe essere un approccio valido, ed è in effetti per i ritorni non locali, ma è comunque una cattiva pratica utilizzarlo ampiamente nel codice. L'utilizzo di resi non locali rende molto difficile per gli altri programmatori comprendere il codice e rende più difficile il debug. Anche se non è progettato specificamente per la gestione degli errori, la gestione degli errori è generalmente l'unico posto in cui dovresti usarlo. Inoltre, se si sta codificando per la gestione degli errori, non si sta seguendo una filosofia di base di Erlang, che è "codice per il successo": si sta pensando più come un programmatore imperativo. – Tim

12

P corrispondenza attern è un buon modo di refactoring una dichiarazione caso - si può fare qualcosa di simile

testcase(1, X, Y) -> .... passed1; 
testcase(2, X, Y) -> .... passed2; 
testcase(N, X, Y) when N > 2 -> .... passedlarge; 
testcase(_, X, Y) -> defaultcase. 

e quindi la sua dichiarazione caso avvolge semplicemente fino a:

X = testcase(Number, Param1, Param2). 

(X sarà o passed1, passed2 , passedlarge o defaultcase in questo esempio inventato)

+1

Ok, sembra fantastico, grazie! – jeffreyveon

2

Un modo è quello di collegare in cascata i vostri casi di dichiarazioni:

my_fun(X) -> 
    case cond1(X) of 
    true -> ret1; 
    _ -> 
     case cond2(X) of 
     true -> ret2; 
     _ -> 
      ... 
     end 
    end. 

Un altro è quello di separare le istruzioni case in clausole:

my_fun(X) -> 
    my_fun(cond1, X). 

my_fun(cond1, X) -> 
    case cond1(X) of 
    true -> ret1; 
    _ -> my_fun(cond2, X) 
    end; 

my_fun(cond2, X) -> 
    case cond2(X) of 
    true -> ret2; 
    _ -> my_fun(cond3, X) 
    end; 

...