简体   繁体   English

即使在使用 isInstanceOf 检查类型后 Scala 类型不匹配错误

[英]Scala type mismatch error even after checking type with isInstanceOf

I have a function unlist taking as first argument a list of any type:我有一个函数unlist将任何类型的列表作为第一个参数:

def unlist(xs: List[Any], ys: List[Any]): List[Any] = ...

and I call this function on the first element of an external list, which may or may not be a list of lists.我在外部列表的第一个元素上调用这个函数,它可能是也可能不是列表。 Thus, I first need to check if this head element is itself a list, in which case I can call my unlist function.因此,我首先需要检查这个 head 元素本身是否是一个列表,在这种情况下我可以调用我的unlist函数。 I do it with InsintanceOf method, like so:我用InsintanceOf方法来做,就像这样:

...
if (xs.head.isInstanceOf[List[Any]]) unlist(xs.head, ys)

However, this does not compile because of a type mismatch on xs.head:但是,由于 xs.head 上的类型不匹配,这不会编译:

Error: type mismatch;
found   : Any
required: List[Any]

What am I doing wrong?我究竟做错了什么?


PS : since many of you have suggested to avoid type Any , I have to specify that this is part of a coding exercise aiming at having a function as general as possible PS :由于你们中的许多人建议避免使用Any类型,我必须指出这是编码练习的一部分,旨在使函数尽可能通用

To illustrate Mateusz's comment为了说明 Mateusz 的评论

isInstanceOf is not being remembered isInstanceOf没有被记住

it is meant we would have to follow up with asInstanceOf like so这意味着我们必须像这样跟进asInstanceOf

if (list.head.isInstanceOf[List[_]]) unlist(list.head.asInstanceOf[List[_]])

Pattern matching, as demonstrated by Tim, implicitly performs isInstanceOf/asInstanceOf combination.模式匹配,如 Tim 所演示的,隐式执行isInstanceOf/asInstanceOf组合。 Also consider related answer .还可以考虑相关答案

If you are unable to refactor out Any , which is the weakest of types, maybe try to recover as much typing information as early as possible, perhaps like so如果您无法重构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 }

Note due to type erasure we cannot easily do much better than List[List[_]] , for example, the following assertion passes请注意,由于类型擦除,我们不能轻易做得比List[List[_]]好得多,例如,以下断言通过

val list: List[Any] = List(List("woo", "hoo"), 42, "kerfuffle")
assert(list.head.isInstanceOf[List[Double]])

In this last case, a compiler warning will tell you that type argument Double in type List[Double] (the underlying of List[Double]) is unchecked since it is eliminated by erasure .在最后一种情况下,编译器警告会告诉您type argument Double in type List[Double] (the underlying of List[Double]) is unchecked since it is eliminated by erasure It is usually not a good idea to ignore such warnings.忽略此类警告通常不是一个好主意。

As mentioned in the comments, using Any like this is the sign of some bad design choices.正如评论中提到的,像这样使用Any是一些糟糕设计选择的标志。 But for the specific problem you have , you can change your if to a match like this:但是对于您遇到的特定问题,您可以将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 _ =>
}

The match checks that the head value is List[Any] then assigns the value to a variable l which has type List[Any] and can therefore be used in the unlist call. match检查头部值是否为List[Any]然后将该值分配给类型为List[Any]的变量l ,因此可以在unlist调用中使用。

Note : This only works because you are testing for List[Any] .注意:这仅适用于您正在测试List[Any] You cannot test for a list of a specific type (eg List[Int] ) because a process called type erasure removes the runtime information that would be required for this to work.您无法测试特定类型的列表(例如List[Int] ),因为称为类型擦除的进程会删除运行时信息,而此信息将需要此操作。 The compiler will warn you when it can't implement a match for this reason.当编译器因此无法实现match时,它会警告您。

The real solution to this question is to fix the design to use specific types rather than Any .这个问题的真正解决方案是修复设计以使用特定类型而不是Any

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM