Scala Language
Per le espressioni
Ricerca…
Sintassi
- per il corpo di {clauses}
- per {clausole} cedere il corpo
- per (clausole) del corpo
- per (clausole) cedere il corpo
Parametri
Parametro | Dettagli |
---|---|
per | Parola chiave richiesta per utilizzare un ciclo / comprensione for |
clausole | L'iterazione e i filtri su cui lavora per. |
dare la precedenza | Usalo se vuoi creare o "cedere" una collezione. L'utilizzo di yield farà sì che il tipo di reso di for sia una raccolta anziché Unit . |
corpo | Il corpo dell'espressione for, eseguito su ogni iterazione. |
Basic For Loop
for (x <- 1 to 10)
println("Iteration number " + x)
Ciò dimostra iterando una variabile, x
, da 1
a 10
e facendo qualcosa con quel valore. Il tipo di ritorno di questo for
comprensione è Unit
.
Di base per la comprensione
Ciò dimostra un filtro su un ciclo for e l'uso della yield
per creare una "comprensione della sequenza":
for ( x <- 1 to 10 if x % 2 == 0)
yield x
L'output per questo è:
scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
A per la comprensione è utile quando è necessario creare una nuova collezione basata sull'iterazione e sui suoi filtri.
Nested For Loop
Questo mostra come puoi scorrere su più variabili:
for {
x <- 1 to 2
y <- 'a' to 'd'
} println("(" + x + "," + y + ")")
(Si noti che to
qui è un metodo operatore infisso che restituisce un range inclusivo . Si veda la definizione qui .)
Questo crea l'output:
(1,a)
(1,b)
(1,c)
(1,d)
(2,a)
(2,b)
(2,c)
(2,d)
Nota che questa è un'espressione equivalente, usando parentesi invece di parentesi:
for (
x <- 1 to 2
y <- 'a' to 'd'
) println("(" + x + "," + y + ")")
Per ottenere tutte le combinazioni in un singolo vettore, possiamo yield
il risultato e impostarlo su un valore val
:
val a = for {
x <- 1 to 2
y <- 'a' to 'd'
} yield "(%s,%s)".format(x, y)
// a: scala.collection.immutable.IndexedSeq[String] = Vector((1,a), (1,b), (1,c), (1,d), (2,a), (2,b), (2,c), (2,d))
Monadico per le comprensioni
Se hai diversi oggetti di tipi monadici , possiamo ottenere combinazioni dei valori usando un 'per comprensione':
for {
x <- Option(1)
y <- Option("b")
z <- List(3, 4)
} {
// Now we can use the x, y, z variables
println(x, y, z)
x // the last expression is *not* the output of the block in this case!
}
// This prints
// (1, "b", 3)
// (1, "b", 4)
Il tipo di ritorno di questo blocco è Unit
.
Se gli oggetti sono dello stesso tipo monadico M
(es. Option
), allora usando yield
restituirà un oggetto di tipo M
invece di Unit
.
val a = for {
x <- Option(1)
y <- Option("b")
} yield {
// Now we can use the x, y variables
println(x, y)
// whatever is at the end of the block is the output
(7 * x, y)
}
// This prints:
// (1, "b")
// The val `a` is set:
// a: Option[(Int, String)] = Some((7,b))
Si noti che la parola chiave yield
non può essere utilizzata nell'esempio originale, dove esiste un mix di tipi monadici ( Option
ed List
). Provare a farlo produrrà un errore di mancata corrispondenza di tipo in fase di compilazione.
Scorrere le raccolte utilizzando un ciclo For
Questo dimostra come stampare ogni elemento di una mappa
val map = Map(1 -> "a", 2 -> "b")
for (number <- map) println(number) // prints (1,a), (2,b)
for ((key, value) <- map) println(value) // prints a, b
Questo dimostra come stampare ogni elemento di una lista
val list = List(1,2,3)
for(number <- list) println(number) // prints 1, 2, 3
Desugaring per le comprensioni
for
comprensione in Scala sono solo zucchero sintattico . Queste comprensioni sono implementate usando i withFilter
, foreach
, flatMap
e map
dei loro tipi di soggetto. Per questo motivo, solo i tipi che hanno questi metodi definiti possono essere utilizzati in termini for
comprensione.
A for
comprensione del seguente modulo, con pattern pN
, generatori gN
e condizioni cN
:
for(p0 <- x0 if g0; p1 <- g1 if c1) { ??? }
... withFilter
le chiamate nidificate usando withFilter
e foreach
:
g0.withFilter({ case p0 => c0 case _ => false }).foreach({
case p0 => g1.withFilter({ case p1 => c1 case _ => false }).foreach({
case p1 => ???
})
})
Considerando che un espressione for
/ yield
della seguente forma:
for(p0 <- g0 if c0; p1 <- g1 if c1) yield ???
... ridurrà lo zucchero alle chiamate annidate usando withFilter
e sia flatMap
che map
:
g0.withFilter({ case p0 => c0 case _ => false }).flatMap({
case p0 => g1.withFilter({ case p1 => c1 case _ => false }).map({
case p1 => ???
})
})
(Nota che la map
è usata nella comprensione più interna, e flatMap
è usato in ogni comprensione esterna.)
A for
comprensione può essere applicato a qualsiasi tipo implementando i metodi richiesti dalla rappresentazione de-zuccherata. Non ci sono restrizioni sui tipi di ritorno di questi metodi, purché siano componibili.