JavaのListはScalaのfor文でそのまま使えない
こんなエラーで30分ハマった。foreach文使ってないのに、なんでforeachという単語がでてくるかに早く着目すべきだった。このエラーは「for文で使える型じゃないよ」という意味合いのようです。
value foreach is not a member of java.util.Set[String]
実際にエラーがでたコード
import com.mongodb.Mongo import com.mongodb.DB import com.mongodb.DBCollection import com.mongodb.BasicDBObject import com.mongodb.DBObject import com.mongodb.DBCursor object MG { def main(args: Array[String]) = { val m = new Mongo("localhost", 27017) val db = m.getDB("mydb") val colls = db.getCollectionNames() //(1) for (s <- colls) { println(s) } } }
MongoDBのJavaチュートリアル見てScalaで書いてたんだけど、エラーが消えない。
型がおかしいことにはすぐ気づいたので、(1)の戻り値が不明確なのかなとか思い、
val colls: java.util.Set[String]
とか型推論に頼らず、直指定で書いてみたり、import文なおしてみたりしたけどダメ。型の指定が不明確なのは関係なかったです。getCollectionNames()は、java.util.Set[String]を返すのですが、それをそのままfor文に使っちゃダメということでした。
Scalaのfor文はscala.collection.Listやscala.collection.Setでならそのまま使えるけど、java.util.Listやjava.util.Setでは使えません。
同じListでも実装が別物だし、"Scalaのfor文"なので、当然JavaのAPIに合わせてるわけじゃなく、Scala標準APIに合わせているはずですよね。
この場合、JavaのListをScalaのListへと変換してあげる必要があります。
import com.mongodb.Mongo import com.mongodb.DB import com.mongodb.DBCollection import com.mongodb.BasicDBObject import com.mongodb.DBObject import com.mongodb.DBCursor import scala.collection.JavaConversions._ //(2) object MG { def main(args: Array[String]) = { val m = new Mongo("localhost", 27017) val db = m.getDB("mydb") val colls = db.getCollectionNames() for (s <- asSet(colls)) { //(3) println(s) } } }
(2)で変換用の関数をimportして、(3)でasSet()関数使えば解決。対象がListならasList()関数。
なお、Scala2.7系ではscala.collection.jcl.Conversionsでした。関数名も違います。2.8系からscala.collection.JavaConversionsとなったので、注意してください。