2013-10-26 10 views
8

sto imparando paradigmi di programmazione nella mia università e la lettura di questo materiale didattico fornito dal docente che ha definito una funzione in questo modo:DEF o val per definire la funzione a Scala

val double = (x: Int) => 2 * x 
double: Int => Int = <function1> 

Ma dai miei studi ho trovato e mi sono abituato a definire la stessa funzione come questa:

def d (x: Int) = 2 * x 
d: (x: Int)Int 

Sono nuovo di Scala. Ed entrambe le definizioni di danno a seguito di:

res21: Int = 8 

Appena passato 4 come parametro. Ora la mia domanda principale è perché il docente preferirebbe usare val per definire una funzione? Lo vedo più a lungo e non è davvero necessario a meno che l'uso di val offra alcuni vantaggi aggiuntivi che non conosco. Inoltre capisco che l'uso di val faccia diventare un segnaposto un nome così in un secondo momento nel programma, potrei scrivere per errore val double = 5 e la funzione sarebbe sparita! In questa fase sono abbastanza convinto di aver imparato un modo migliore di definire una funzione a meno che qualcuno non mi dicesse diversamente.

+0

Non sono qualificato per dire qualcosa di definitivo su Scala, ma hai provato a fare effettivamente 'val double = 5' dopo che la funzione è stata definita' double'? Ho l'impressione che dovrebbe essere impossibile ridefinire un nome una volta definito. In ogni caso, sia 'val' che' def' producono qui lo stesso risultato. La differenza è semplicemente stilistica. Spesso, è più chiaro definire una funzione con 'def', ma a volte ha senso definirla con' val'. Se non sei sicuro, ti consiglierei di usare 'def', poiché è meno probabile che causi confusione. – kqr

+0

Sì, ho eseguito 'val double = 5', ho digitato' double' e ottenuto 'res24: Int = 5' – Emanuel

+0

possibile duplicato di [Differenza tra metodo e funzione in Scala] (http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala) –

risposta

12

In senso stretto, def d (x: Int) = 2 * x è un metodo, non una funzione, tuttavia scala può convertire in modo trasparente i metodi (ascensore) in Funzioni per noi. In questo modo è possibile utilizzare il metodo d in qualsiasi punto che richiede una funzione Int => Int.

Esiste un piccolo sovraccarico di esecuzione di questa conversione, poiché ogni volta viene creata una nuova istanza di funzione. Possiamo vedere questo accade qui:

val double = (x: Int) => 2 * x 
def d (x: Int) = 2 * x 

def printFunc(f: Int => Int) = println(f.hashCode()) 

printFunc(double) 
printFunc(double) 
printFunc(d) 
printFunc(d) 

che si traduce in uscita in questo modo:

1477986427 
1477986427 
574533740 
1102091268 

si può vedere quando si definisce esplicitamente una funzione utilizzando un val, il nostro programma crea solo una singola funzione e riutilizza quando passiamo come argomento a printFunc (vediamo lo stesso codice hash). Quando usiamo un def, la conversione in una funzione avviene ogni volta che la passiamo a printFunc e creiamo diverse istanze della funzione con diversi codici hash. Try it

Detto questo, il sovraccarico delle prestazioni è piccolo e spesso non fa alcuna differenza reale per il nostro programma, in modo da def s sono spesso utilizzati per definire le funzioni come molte persone trovano loro più conciso e più facile da leggere.

+2

[Some guy] (http://japgolly.blogspot.com.au/2013/10/scala-methods-vs-functions.html) ha pubblicato un benchmark di recente, dimostrando che "eta-expansion" (solleva un metodo per una funzione quando lo si passa come argomento) in realtà non incorre in una penalizzazione delle prestazioni. –

+0

Bel post. Immagino che ci possa essere anche un aumento nella raccolta dei rifiuti, ma immagino che sarà anche un piccolo/inesistente. – theon

0

perché si potrebbe avere qualcosa di simile a quanto segue:

abstract class BaseClass { 
    val intToIntFunc: Int => Int 
} 

class A extends BaseClass { 
    override val intToIntFunc = (i: Int) => i * 2 
} 

Così il suo scopo potrebbe non essere evidente con un esempio molto semplice. Ma quel valore Function potrebbe essere passato a funzioni di ordine superiore: funzioni che assumono funzioni come parametri. Se si guarda nella documentazione delle collezioni Scala si vedranno numerosi metodi che assumono funzioni come parametri. È uno strumento molto potente e versatile, ma è necessario raggiungere una certa complessità e familiarità con gli algoritmi prima che il rapporto costi/benefici diventi ovvio.

Vorrei anche suggerire di non utilizzare "double" come nome identificativo. Sebbene Scala legale, è facile confonderlo con il tipo Double.

5

In Scala, i valori delle funzioni sono monomorfici (ovvero non possono avere parametri di tipo, ovvero "generici").Se si desidera una funzione polimorfica, si deve ovviare a questo, ad esempio definendo impiegando un metodo:

def headOption[A]: List[A] => Option[A] = { 
    case Nil => None 
    case x::xs => Some(x) 
} 

Non sarebbe sintassi valida di scrivere val headOption[A]. Si noti che questo non ha prodotto un valore di funzione polimorfico, è solo un metodo polimorfico, restituendo un valore di funzione monomorfico del tipo appropriato.

+0

+1 è una differenza importante da conoscere – theon

Problemi correlati