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.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow