[英]Scala type disagreement between compiler and run-time?
從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
對此有什么簡單的解釋? 我怎樣才能更好地接近轉換?
JavaConverters轉換為最接近它已經拉皮條的Java集合的Scala集合。 您仍然需要調用toList以進一步將其轉換為您想要的集合:
val emits = emitsJ.asScala.toList map (i => i.getKeyword)
trie.parseText
的返回類型聲明為java.util.Collection[Emit]
。 這不是很具體,有很多可能的Collection
子類型,它們沒有指定它們要返回的具體類型,它可以是TreeSet
,它可以是Vector
,也可以是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
上調用map並獲得一個Iterable
。
現在,就像你已經檢查了從parseText返回的Collection
的運行時值,並且看到它是一個ArrayList
你已經檢查了從這個map操作返回的值,並且看到它是一個scala.collection.immutable.List
,但是,編譯器無法知道這一點,它可以知道的是你得到的東西是Iterable
的子類。
只需在生成的Iterable
上調用.toList就可以了。
所以這里發生的事情是從asScala
返回給你的底層對象是一個List
但它已經被asScala
到Iterable
因為List <: Iterable
這一切都很好,直到你想把Iterable
用作列表。 最簡單的選擇是調用toList
。
有關更多詳細信息,您可以瀏覽源代碼 :
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
的調用asScala
你回到這個包裝器。 接下來,你對map的調用正在使用這個 CanBuildFrom
,然后在這個map操作中使用它 ,它最終會給你一個恰好是List
的結果,因為構建器是一個ListBuffer
而且result
是一個List
,它同樣恰好是一個List
Iterable
,因為可以建立從模式向下轉換到Iterable
。 希望能解釋一切:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.