[英]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 rememberedisInstanceOf
没有被记住
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.