2011-12-22 13 views
44

dato:Scala Mappa foreach

val m = Map[String, Int]("a" -> 1, "b" -> 2, "c" -> 3) 
m.foreach((key: String, value: Int) => println(">>> key=" + key + ", value=" + value)) 

Perché il compilatore si lamentano

error: type mismatch 
found : (String, Int) => Unit 
required: (String, Int) => ? 

risposta

25

oops, leggere il doco sbagliato, map.foreach si aspetta un valore letterale di funzione con un argomento tupla!

così

m.foreach((e: (String, Int)) => println(e._1 + "=" + e._2)) 

funziona

+4

Dato che i tipi coinvolti sono dedotti, si potrebbe semplicemente fare: m.foreach (e => println (e._1 + "=" + e._2) – virtualeyes

+0

È possibile mostrare il tipo completo? Ci sono molte mappe , Sono preoccupato di quale di questi si tratta –

71

io non sono sicuro circa l'errore, ma è possibile ottenere ciò che si vuole come segue:

m.foreach(p => println(">>> key=" + p._1 + ", value=" + p._2)) 

Vale a dire, foreach accetta una funzione che accetta una coppia e restituisce Unit, non una funzione t cappello prende due argomenti: qui, p ha tipo (String, Int).

Un altro modo per scrivere è:

m.foreach { case (key, value) => println(">>> key=" + key + ", value=" + value) } 

In questo caso, il blocco { case ... } è una funzione parziale.

+0

che è bello, più in linea con obj.each linguaggio dinamico approccio {k, v => ...} e altro ancora leggibile della tupla ._1, ._2 sintassi – virtualeyes

+0

Juts curioso, c'è qualche considerazione prestazionale per il secondo utilizzo (caso)? Per ogni elemento prova a 'caso' assegnarli alla variabile ecc. Voglio che il mio codice sia leggibile ma anche il più veloce possibile. – endertunc

13

È necessario eseguire il patter-match sull'argomento Tuple2 per assegnare le variabili alle sue sottoparti key, value. Si può fare con pochissime modifiche:

m.foreach{ case (key: String, value: Int) => println(">>> key=" + key + ", value=" + value)} 
+5

Ed è possibile rimuovere annotazioni di tipo da chiave e valore, a proposito. – Rogach

+0

@huitseeker Ti amo molto caro. –

5

Ottima domanda! Anche quando si digita esplicitamente il metodo foreach, si ottiene comunque un errore di compilazione molto poco chiaro. Ci sono modi per aggirarlo, ma non riesco a capire perché questo esempio non funzioni.

scala> m.foreach[Unit] {(key: String, value: Int) => println(">>> key=" + key + ", value=" + value)} 
<console>:16: error: type mismatch; 
found : (String, Int) => Unit 
required: (String, Int) => Unit 
       m.foreach[Unit] {(key: String, value: Int) => println(">>> key=" + key + ", value=" + value)} 
                 ^
14

Il messaggio di errore di confusione è un bug del compilatore, che dovrebbe essere fixed in 2.9.2:

+0

Utilizzo di scalac 2.9.2 e questo errore rimane – Renato

+0

Ho appena controllato (compilando https://github.com/paulbutcher/baderrormessage contro entrambi 2.9.1 e 2.9. 2). Posso vedere il problema in 2.9.1 e non in 2.9.2.Se hai ancora un esempio del problema, forse dovresti riaprire il bug? –

+0

Ho appena provato il codice inserito nella risposta da @ (Eishay Smith) di seguito (credo sia lo stesso identico problema mostrato nella domanda) con Scala 2.9.2 (Java HotSpot 1.7.0 VM per Windows 64-bit) e può vedere lo stesso messaggio assurdo mostrato nel suo post. – Renato

0

Ancora un altro modo:

Map(1 -> 1, 2 -> 2).foreach(((x: Int, y: Int) => ???).tupled) 

Tuttavia essa richiede le annotazioni di tipo esplicite, quindi preferisco funzioni parziali.

1

Docs dice argomento è tupla -> unità, in modo che possiamo facilmente fare questo

Map(1 -> 1, 2 -> 2).foreach(tuple => println(tuple._1 +" " + tuple._2)))