[英]Scala type mismatch error even after checking type with isInstanceOf
我有一個函數unlist
將任何類型的列表作為第一個參數:
def unlist(xs: List[Any], ys: List[Any]): List[Any] = ...
我在外部列表的第一個元素上調用這個函數,它可能是也可能不是列表。 因此,我首先需要檢查這個 head 元素本身是否是一個列表,在這種情況下我可以調用我的unlist
函數。 我用InsintanceOf
方法來做,就像這樣:
...
if (xs.head.isInstanceOf[List[Any]]) unlist(xs.head, ys)
但是,由於 xs.head 上的類型不匹配,這不會編譯:
Error: type mismatch;
found : Any
required: List[Any]
我究竟做錯了什么?
PS :由於你們中的許多人建議避免使用Any
類型,我必須指出這是編碼練習的一部分,旨在使函數盡可能通用
為了說明 Mateusz 的評論
isInstanceOf
沒有被記住
這意味着我們必須像這樣跟進asInstanceOf
if (list.head.isInstanceOf[List[_]]) unlist(list.head.asInstanceOf[List[_]])
模式匹配,如 Tim 所演示的,隱式執行isInstanceOf/asInstanceOf
組合。 還可以考慮相關答案。
如果您無法重構Any
,這是最弱的類型,也許嘗試盡早恢復盡可能多的類型信息,也許像這樣
val lists: List[List[_]] = list.collect { case xs: List[_] => xs }
val ints: List[Int] = list.collect { case i: Int => i }
val strings: List[String] = list.collect { case s: String => s }
請注意,由於類型擦除,我們不能輕易做得比List[List[_]]
好得多,例如,以下斷言通過
val list: List[Any] = List(List("woo", "hoo"), 42, "kerfuffle")
assert(list.head.isInstanceOf[List[Double]])
在最后一種情況下,編譯器警告會告訴您type argument Double in type List[Double] (the underlying of List[Double]) is unchecked since it is eliminated by erasure
。 忽略此類警告通常不是一個好主意。
正如評論中提到的,像這樣使用Any
是一些糟糕設計選擇的標志。 但是對於您遇到的特定問題,您可以將if
更改為這樣的match
:
def unlist(xs: List[Any], ys: List[Any]): List[Any] = ???
val xs: List[Any] = ???
xs.head match {
case l: List[Any] => unlist(l, ???)
case _ =>
}
match
檢查頭部值是否為List[Any]
然后將該值分配給類型為List[Any]
的變量l
,因此可以在unlist
調用中使用。
注意:這僅適用於您正在測試List[Any]
。 您無法測試特定類型的列表(例如List[Int]
),因為稱為類型擦除的進程會刪除運行時信息,而此信息將需要此操作。 當編譯器因此無法實現match
時,它會警告您。
這個問題的真正解決方案是修復設計以使用特定類型而不是Any
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.