2011-09-28 5 views
13

Per favore, pazienza con me, sono ancora piuttosto noobish con Scala. Ho il seguente codice:java.util.Iterator all'elenco Scala?

private lazy val keys : List[String] = obj.getKeys().asScala.toList 

obj.getKeys restituisce un java.util.Iterator

Calling asScala, tramite JavaConverers (che viene importato) Secondo la documentazione ..

java.util.Iterator <==> scala.collection.Iterator 

scala.collection.Iterator definisce

def toList : List[A] 

Quindi, in base a questo ho creduto che questo dovrebbe funzionare, howev er ecco l'errore di compilazione.

[scalac] <file>.scala:11: error: type mismatch; 
[scalac] found : List[?0] where type ?0 
[scalac] required: List[String] 
[scalac] private lazy val keys : List[String] = obj.getKeys().asScala.toList 
[scalac] one error found 

Capisco il parametro di tipo o l'Iterator Java è una stringa Java, e che sto cercando di creare una lista di stringhe Scala, ma (forse ingenuamente) pensato che ci sarebbe stata una conversione implicita.

risposta

10

Che funzionerebbe se obj.getKeys() fosse un java.util.Iterator<String>. Suppongo che non lo sia.

Se obj.getKeys() è solo java.util.Iterator in forma grezza, non java.util.Iterator<String>, nemmeno java.util.Iterator<?>, questo è qualcosa scala tendono ad antipatie, ma in ogni caso, non c'è modo Scala sarà digitare l'espressione come List[String] se non ha alcuna garanzia obj.getKeys() contiene la stringa .

Se si conosce l'iteratore è in stringhe, ma il tipo non lo dice, si può lanciare:

obj.getKeys().asInstanceOf[java.util.Iterator[String]] 

(poi andare avanti con .asScala.toList)

Si noti che, proprio come in Java e a causa della cancellazione del tipo, il cast non verrà controllato (verrà visualizzato un avviso). Se si vuole verificare subito di avere le stringhe, si può invece fare

obj.getKeys().map(_.asInstanceOf[String]) 

che controllerà il tipo di ciascun elemento, mentre eseguire iterazioni per creare l'elenco

+1

Grazie mille per la risposta! sembra che tu e Matthew Farwell siate d'accordo per la maggior parte. Ho fatto quello che mi hai suggerito, obj.getKeys(). AsInstanceOf [java.util.Iterator [String]]. AsScala.toList e sembra funzionare, e non ho ricevuto un avviso di compilazione. – rshepherd

24

Non è necessario chiamare asScala, è una conversione implicita:

import scala.collection.JavaConversions._ 

val javaList = new java.util.LinkedList[String]() // as an example 

val scalaList = javaList.iterator.toList 

Se davvero non hanno il parametro tipo di iteratore, solo il cast al tipo corretto:

MODIFICA: alcune persone preferiscono non utilizzare le conversioni implicite in JavaConversions, ma utilizzano i decoratori asScala/asJava in JavaConverters per rendere le conversioni più esplicite.

+0

Avete ragione, non esiste un parametro di tipo per l'Iterator che viene restituito dal metodo getKeys(). Osservazione molto astuta, grazie. Anche se sembra che io abbia bisogno dell'asScala lì dentro, in quel caso. Forse c'è qualcos'altro che mi manca. – rshepherd

+0

La conversione implicita è su 'JavaConversions', ma non su' JavaConverters'. Quello usa 'asScala'. Molte persone, me compreso, preferiscono rendere esplicita questa conversione per evitare bug sottili. –

+0

@Daniel Immagino che rendere le cose esplicite sia una buona idea, grazie per il suggerimento. –

3

non mi piace le altre risposte. Diavolo, non mi piace tutto ciò che suggerisce l'uso di asInstanceOf a meno che non ci sia alternativa. In questo caso, c'è. Se si esegue questa operazione:

private lazy val keys : List[String] = obj.getKeys().asScala.collect { 
    case s: String => s 
}.toList 

Si accende il Iterator[_] in un Iterator[String] modo sicuro ed efficiente.