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 .