簡體   English   中英

Scala類型在編譯器和運行時之間存在分歧嗎?

[英]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)

請參閱相關: Scala中JavaConverters和JavaConversions之間的區別是什么?

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但它已經被asScalaIterable因為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM