从java.util.ArrayList
转换为scala.collection.immutable.List
,2.10编译器和运行时似乎存在分歧,关于val emits
的类型:
import org.ahocorasick.trie._
import scala.collection.JavaConverters._ // convert Java colllections to Scala ones
object wierd {
val trie = new Trie
def trieInit(patterns: List[String]) {
trie.onlyWholeWords();
for (pattern <- patterns)
trie.addKeyword(pattern)
}
def patternTest(text : String) : List[String] =
{
val emitsJ = trie.parseText(text)
val emits = emitsJ.asScala map (i => i.getKeyword)
println(s"converted from ${emitsJ.getClass} to ${emits.getClass}")
//return(emits)
return (List.empty[String])
}
trieInit(List("hello"))
patternTest("hello")
}
收率:
converted from class java.util.ArrayList to class scala.collection.immutable.$colon$colon
现在更改为仅通过更改return
行 -
import org.ahocorasick.trie._
import scala.collection.JavaConverters._ // convert Java colllections to Scala ones
object wierd {
val trie = new Trie
def trieInit(patterns: List[String]) {
trie.onlyWholeWords();
for (pattern <- patterns)
trie.addKeyword(pattern)
}
def patternTest(text : String) : List[String] =
{
val emitsJ = trie.parseText(text)
val emits = emitsJ.asScala map (i => i.getKeyword)
println(s"converted from ${emitsJ.getClass} to ${emits.getClass}")
return(emits)
//return (List.empty[String])
}
trieInit(List("hello"))
patternTest("hello")
}
产生编译错误:
[error] reproduce.scala:23: type mismatch;
[error] found : Iterable[String]
[error] required: List[String]
[error] return(emits)
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
对此有什么简单的解释? 我怎样才能更好地接近转换?
答案 0 :(得分:1)
JavaConverters转换为最接近它所拥有的Java集合的Scala集合。您仍然需要调用toList以进一步将其转换为您想要的集合:
val emits = emitsJ.asScala.toList map (i => i.getKeyword)
参见相关内容:What is the difference between JavaConverters and JavaConversions in Scala?
答案 1 :(得分:1)
trie.parseText
的返回类型声明为java.util.Collection[Emit]
。这不是非常具体,Collection
有很多可能的子类型,它们没有指定它们要返回的具体类型,它可能是TreeSet
,它可能是Vector
1}},它可能是ArrayList
。但就编译器而言,它可能是Collection
的子类型。您已经在运行时检查过它,并发现对于某些特定输入,它碰巧返回ArrayList
,但编译器无法知道这一点。
当您在此调用.asScala时,您正在使用JavaConverters
implicit def iterableAsScalaIterableConverter[A](i: java.lang.Iterable[A]): convert.Decorators.AsScala[Iterable[A]]
将java.lang.Itaerable转换为scala.collection.Iterable。
Collection
没有转换器,因此您可以获得下一个最具体的转换器Iterable
。您在此Iterable
上调用地图并返回Iterable
。
现在,就像你已经检查了从parseText返回的Collection
的运行时值,看到它是ArrayList
你已经检查了这个map操作返回的值,并且看到它是一个scala.collection.immutable.List
,但同样,编译器无法知道这一点,它可以知道的是你得到的东西是Iterable
的子类。
只需在生成的Iterable
上调用.toList就可以了。
答案 2 :(得分:1)
所以这里发生的事情是从asScala
返回给你的基础对象是List
,但是从Iterable
开始被归为List <: Iterable
,这一切都很好,直到您想使用Iterable
作为列表。最简单的选择是在其上调用toList
。
有关详细信息,您可以浏览source:
case class JCollectionWrapper[A](underlying: ju.Collection[A]) extends AbstractIterable[A] with Iterable[A] {
def iterator = underlying.iterator
override def size = underlying.size
override def isEmpty = underlying.isEmpty
def newBuilder[B] = new mutable.ArrayBuffer[B]
}
所以你对asScala
的调用会让你回到这个包装器。接下来,您对地图的调用是使用this CanBuildFrom
,然后在this map operation中使用,最后会为您提供恰好是List
的结果,因为构建器是ListBuffer
和result
是List
,它恰好是Iterable
,因为它可以从模式向下转换为Iterable
。希望能解释一切:)