Scala Language
funzioni
Ricerca…
Osservazioni
Scala ha funzioni di prima classe.
Differenza tra funzioni e metodi:
Una funzione non è un metodo in Scala: le funzioni sono un valore e possono essere assegnate come tali. I metodi (creati usando def ), d'altra parte, devono appartenere a una classe, un tratto o un oggetto.
- Le funzioni sono compilate in una classe che estende un tratto (come
Function1) in fase di compilazione e sono istanziate a un valore in fase di esecuzione. I metodi, d'altra parte, sono membri della loro classe, tratto o oggetto e non esistono al di fuori di questo. - Un metodo può essere convertito in una funzione, ma una funzione non può essere convertita in un metodo.
- I metodi possono avere la parametrizzazione dei tipi, mentre le funzioni no.
- I metodi possono avere valori di default dei parametri, mentre le funzioni no.
Funzioni anonime
Le funzioni anonime sono funzioni definite ma non assegnate a un nome.
La seguente è una funzione anonima che accetta due interi e restituisce la somma.
(x: Int, y: Int) => x + y
L'espressione risultante può essere assegnata a un val :
val sum = (x: Int, y: Int) => x + y
Le funzioni anonime vengono principalmente utilizzate come argomenti per altre funzioni. Ad esempio, la funzione map su una raccolta prevede un'altra funzione come argomento:
// Returns Seq("FOO", "BAR", "QUX")
Seq("Foo", "Bar", "Qux").map((x: String) => x.toUpperCase)
I tipi di argomenti della funzione anonima possono essere omessi: i tipi vengono dedotti automaticamente :
Seq("Foo", "Bar", "Qux").map((x) => x.toUpperCase)
Se c'è un solo argomento, le parentesi attorno a quell'argomento possono essere omesse:
Seq("Foo", "Bar", "Qux").map(x => x.toUpperCase)
Sottolinea la stenografia
C'è una sintassi ancora più breve che non richiede nomi per gli argomenti. Lo snippet sopra riportato può essere scritto:
Seq("Foo", "Bar", "Qux").map(_.toUpperCase)
_ rappresenta gli argomenti della funzione anonima in modo posizionale. Con una funzione anonima che ha più parametri, ogni occorrenza di _ farà riferimento a un argomento diverso. Ad esempio, le due espressioni seguenti sono equivalenti:
// Returns "FooBarQux" in both cases
Seq("Foo", "Bar", "Qux").reduce((s1, s2) => s1 + s2)
Seq("Foo", "Bar", "Qux").reduce(_ + _)
Quando si utilizza questa stenografia, qualsiasi argomento rappresentato da _ posizionale può essere fatto riferimento una sola volta e nello stesso ordine.
Funzioni anonime senza parametri
Per creare un valore per una funzione anonima che non accetta parametri, lascia vuoto l'elenco dei parametri:
val sayHello = () => println("hello")
Composizione
La composizione delle funzioni consente di far funzionare due funzioni e di essere viste come una singola funzione. Espresso in termini matematici, data una funzione f(x) e una funzione g(x) , la funzione h(x) = f(g(x)) .
Quando una funzione viene compilata, viene compilata su un tipo correlato a Function1 . Scala fornisce due metodi nell'implementazione Function1 relativa alla composizione: andThen e compose . Il metodo di compose adatta alla definizione matematica di cui sopra in questo modo:
val f: B => C = ...
val g: A => B = ...
val h: A => C = f compose g
The andThen (penso che h(x) = g(f(x)) ) abbia un sentimento più simile a 'DSL':
val f: A => B = ...
val g: B => C = ...
val h: A => C = f andThen g
Una nuova funzione anonima viene allocato con che è chiuso su f e g . Questa funzione è associata alla nuova funzione h in entrambi i casi.
def andThen(g: B => C): A => C = new (A => C){
def apply(x: A) = g(self(x))
}
Se uno dei due f o g funziona tramite un effetto collaterale, quindi chiamando h causerà tutti gli effetti collaterali di f e g per accadere nell'ordine. Lo stesso vale per qualsiasi cambiamento di stato mutabile.
Relazione con le funzioni parziali
trait PartialFunction[-A, +B] extends (A => B)
Ogni singola funzione PartialFunction è anche una Function1 . Questo è contro-intuitivo in senso matematico formale, ma si adatta meglio alla progettazione orientata agli oggetti. Per questo motivo Function1 non deve fornire un metodo isDefinedAt true isDefinedAt .
Per definire una funzione parziale (che è anche una funzione), utilizzare la seguente sintassi:
{ case i: Int => i + 1 } // or equivalently { case i: Int ⇒ i + 1 }
Per ulteriori dettagli, dare un'occhiata a PartialFunctions .