2012-09-24 11 views
48

Sono un principiante programmatore di scala e ho trovato un comportamento strano.Ritorno in Scala

def balanceMain(elem: List[Char]): Boolean = 
    { 
    if (elem.isEmpty) 
     if (count == 0) 
     true; 
     else false; 

    if (elem.head == '(') 
     balanceMain(elem.tail, open, count + 1);.... 

Sopra fondamentalmente voglio tornare vero se elem.isEmpty e count == 0. Altrimenti, voglio restituire false.

Ora ho letto sopra che non è necessario aggiungere un'istruzione return in scala. Quindi ho omesso lo return sopra. Ma non restituisce il booleano. Se aggiungo un estratto conto come return true. funziona perfettamente. Perché è così?

Inoltre, perché è considerata una cattiva pratica per avere istruzioni return a Scala

+1

C'è ** di solito ** non è necessario per la parola chiave di restituzione, purché si rompa il codice in metodi abbastanza piccoli. – mauhiz

+0

@mauhiz Grazie. Puoi spiegarlo per favore? Come lo farai? – Jatin

+2

sembra che tu stia prendendo il corso Coursera Scala. tutto il meglio :) – weima

risposta

90

Non è così semplice come solo omettendo la parola chiave return. In Scala, se non esiste lo return, l'ultima espressione viene considerata come valore di ritorno. Pertanto, se l'ultima espressione è ciò che si desidera restituire, è possibile omettere la parola chiave return. Ma se quello che vuoi restituire è non l'ultima espressione, quindi Scala non saprai che volevi restituirlo.

Un esempio:

def f() = { 
    if (something) 
    "A" 
    else 
    "B" 
} 

Qui l'ultima espressione della funzione f è un'espressione if/else che restituisce una stringa. Dato che non è stato specificato return esplicito, Scala dedurrà che si desidera restituire il risultato di questa espressione if/else: a String.

Ora, se aggiungiamo qualcosa dopo if/else espressione:

def f() = { 
    if (something) 
    "A" 
    else 
    "B" 

    if (somethingElse) 
    1 
    else 
    2 
} 

Ora l'ultima espressione è un if/else un'espressione che restituisce un int. Quindi il tipo di ritorno di f sarà Int. Se volessimo davvero restituire la stringa, allora siamo nei guai perché Scala ha nessuna idea che è quello che intendevamo. Pertanto, dobbiamo ripararlo memorizzando la stringa su una variabile e restituendola dopo la seconda espressione if/else, oppure modificando l'ordine in modo che la parte String si verifichi per ultima.

Infine, possiamo evitare la parola return anche con un'espressione nidificato if-else come la vostra:

def f() = { 
    if(somethingFirst) { 
    if (something)  // Last expression of `if` returns a String 
    "A" 
    else 
    "B" 
    } 
    else { 
    if (somethingElse) 
     1 
    else 
     2 

    "C"    // Last expression of `else` returns a String 
    } 

}

+1

Di tutti gli dei, grazie! Stavo combattendo con lo stesso problema per ore (facendo anche il corso a Coursera) e non ero in grado di capire perché il ritorno fosse richiesto. –

+0

per il primo esempio, cosa succede se aggiungi ritorni. Io restituisco "A" e "restituisco" B "'? –

+0

@ T.Rex restituirà al chiamante di f() il valore "A" o "B".Ma come ho spiegato nella mia risposta. Non usare mai return in Scala. Se le istruzioni in Scala funzionano in modo funzionale. Valutano qualcosa con un tipo. Come l'operatore ternario in Java (? :). Esempio: val foo = if (miobool) "A" else "B" - foo sarà una stringa contenente "A" o "B". Allo stesso modo, pensa a una funzione che non restituisce qualcosa ma valuta il valore dell'ultima espressione in essa contenuta. – Grmpfhmbl

3

Io non programmo Scala, ma usare un'altra lingua con rendimenti impliciti (Ruby). Hai il codice dopo il tuo blocco if (elem.isEmpty) - l'ultima riga di codice è ciò che viene restituito, motivo per cui non ottieni ciò che ti aspetti.

MODIFICA: ecco un modo più semplice per scrivere anche la tua funzione. Basta utilizzare il valore booleano di isEmpty e contare fino a restituire true o false automaticamente:

def balanceMain(elem: List[Char]): Boolean = 
{ 
    elem.isEmpty && count == 0 
} 
+0

Grazie. Ma voglio solo tornare se elem.isEmpty && count == 0 return true else continua il blocco. Quanto sopra ritornerà anche se è falso. – Jatin

+0

@ Jatin: Ah, non lo sapevo. In questo caso, il ritorno anticipato e "esplicito" sarebbe opportuno. – jmdeldin

+0

@Frank: Né è definito nel codice dell'OP. Ho pensato che fosse una chiamata al metodo. – jmdeldin

4

Per impostazione predefinita l'ultima espressione di una funzione verrà restituito. Nel tuo esempio c'è un'altra espressione dopo il punto, dove vuoi il tuo valore di ritorno. Se si desidera restituire qualcosa prima dell'ultima espressione, è comunque necessario utilizzare return.

è possibile modificare il vostro esempio come questo, per restituire un Boolean dalla prima parte

def balanceMain(elem: List[Char]): Boolean = { 
    if (elem.isEmpty) { 
    // == is a Boolean resulting function as well, so your can write it this way 
    count == 0 
    } else { 
    // keep the rest in this block, the last value will be returned as well 
    if (elem.head == "(") { 
     balanceMain(elem.tail, open, count + 1) 
    } 
    // some more statements 
    ... 
    // just don't forget your Boolean in the end 
    someBoolExpression 
    } 
} 
+9

Non "istruzione". "espressione" –

+1

@ViktorKlang grazie per il suggerimento, corretto. – Tharabas

3

Non scrivere if dichiarazioni senza un corrispondente else. Dopo aver aggiunto else al frammento, vedrai che le tue true e false sono in realtà le ultime espressioni della funzione.

def balanceMain(elem: List[Char]): Boolean = 
    { 
    if (elem.isEmpty) 
     if (count == 0) 
     true 
     else 
     false 
    else 
     if (elem.head == '(') 
     balanceMain(elem.tail, open, count + 1) 
     else.... 
+1

L'ho applicato, ho ottenuto 3 IF annidati e sembra brutto. C'è qualche motivo per renderlo più bello? – Sergey

9

Questo argomento è in realtà un po 'più complicato come descritto nelle risposte finora. Questo blogpost by Rob Norris lo spiega in modo più dettagliato e fornisce esempi su quando utilizzare return in realtà infrange il codice (o almeno ha effetti non ovvi).

A questo punto lasciatemi solo citare l'essenza del post. L'affermazione più importante è proprio all'inizio. Stampa questo come poster e mettilo sulla tua bacheca :-)

La parola chiave return non è "opzionale" o "dedotta"; cambia il significato del tuo programma e non dovresti mai usarlo.

Dà un esempio, dove effettivamente si rompe qualcosa, quando si inline una funzione

// Inline add and addR 
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add 

scala> sum(33, 42, 99) 
res2: Int = 174 // alright 

def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR 

scala> sumR(33, 42, 99) 
res3: Int = 33 // um. 

perché

A return espressione, quando valutata, abbandona il calcolo corrente e ritorna al chiamante del metodo in cui appare return.

Questo è solo uno degli esempi forniti nel post collegato ed è il più semplice da capire. Ce ne sono di più e ti incoraggio molto, andare lì, leggere e capire.

Quando vieni da lingue imperative come Java, all'inizio potrebbe sembrare strano, ma una volta che ti sarai abituato a questo stile avrà senso. Lasciatemi concludere con un'altra citazione:

Se vi trovate in una situazione in cui si pensa che si desidera tornare presto, è necessario ripensare il modo in cui è stato definito il vostro calcolo.

+1

Non sono d'accordo con Rob, IMO non devi usare 'return' solo nelle espressioni lambda, ma questa è una scelta di design di merda nel linguaggio, il codice non dovrebbe nemmeno compilare (in python ciò viene evitato avendo' lambda' parola chiave senza l'istruzione return) ... in tutti gli altri casi non vedo un problema reale nell'uso di 'return' se si desidera restituire un valore (e sì si esce dall'esecuzione del metodo perché è il tipo di ritorno utilizzato in tutte le lingue !) – daveoncode

+0

Sei libero di avere la tua opinione, ma molte persone sono d'accordo sul fatto che usare return in Scala sia per lo meno cattivo stile. Ti sfido a trovare esempi ufficiali di documenti Scala che utilizzano il rendimento. È AFAIK non ancora spiegato nei documenti ufficiali, solo nel documento spec (cap 6.20). Per citare lo stesso Martin Odersky (Programming in Scala) "Lo stile consigliato per i metodi è infatti quello di evitare di avere dichiarazioni esplicite, e in particolare multiple, di ritorno, ma si pensi ad ogni metodo come espressione che restituisce un valore, che viene restituito." Il primo edito di questo libro è disponibile gratuitamente online http://www.artima.com/pins1ed/ – Grmpfhmbl