I have a function unlist
taking as first argument a list of any type:
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. I do it with InsintanceOf
method, like so:
...
if (xs.head.isInstanceOf[List[Any]]) unlist(xs.head, ys)
However, this does not compile because of a type mismatch on 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
To illustrate Mateusz's comment
isInstanceOf
is not being remembered
it is meant we would have to follow up with asInstanceOf
like so
if (list.head.isInstanceOf[List[_]]) unlist(list.head.asInstanceOf[List[_]])
Pattern matching, as demonstrated by Tim, implicitly performs isInstanceOf/asInstanceOf
combination. 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
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
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
. 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. But for the specific problem you have , you can change your if
to a match
like this:
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.
Note : This only works because you are testing for 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. The compiler will warn you when it can't implement a match
for this reason.
The real solution to this question is to fix the design to use specific types rather than Any
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.