Scala:为什么isInstanceOf [List [Any]]不起作用?

时间:2013-07-25 13:16:45

标签: scala

我试图解决99 Scala Problems的问题7,我在确定可以包含任何类型的List的类型时遇到了一些困难。所以我看了答案,发现它是List[Any]。我开始按如下方式编写实现代码:

def flatten(lst: List[Any]): List[Any] = lst match {
    case Nil => Nil
    case x::xs =>
        (if (x.isInstanceOf[List[Any]]) { flatten(x) } else { List(x) }) :::
        flatten(xs)
}

但是,这给了我以下编译错误:

[error] <filename omitted>:<line number omitted>: type mismatch;
[error] found   : Any
[error] required: List[Any]
[error]                (if (x.isInstanceOf[Any]) { flatten(x) } else {List(x) })
[error]                                                    ^
[error] one error found

isInstanceOf[List[Any]]更改为isInstanceOf[List[_]]会产生相同的编译错误。

经过短暂的谷歌搜索和咨询this solution,我实现了这个:

def flatten(lst: List[Any]): List[Any] = lst match {
    case Nil => Nil
    case x::xs => x match {
        case x: List[_] => flatten(x) ::: flatten(xs)
        case _ => x :: flatten(xs)
    }
}

完美无缺。那么为什么Scala编译器认为x具有类型Any时,为了进入该块,它必须通过x.isInstanceOf[Any],这使得它为List[Any]类型?这是一个编译器错误,还是Scala的某些部分,我不明白?

谢谢!

3 个答案:

答案 0 :(得分:3)

在您的代码中,xList[Any]的头部:它是Any,因此您收到错误消息。你需要把它投射到List[Any],这种模式匹配可以让你做得非常优雅:

def flatten(lst: List[Any]): List[Any] = lst match {
  case Nil               => Nil
  case (x:List[Any])::xs => flatten(x) ::: flatten(xs)
  case x::xs             => List(x) ::: flatten(xs)
}

答案 1 :(得分:2)

仅仅因为值通过.isInstanceOf检查不会改变它的类型。它仍然是Any。但它可以转换为List[Any]

所以,我认为你需要做

(if (x.isInstanceOf[List[Any]]) { flatten(x.asInstanceOf[List[Any]]) } else { List(x) }) ::: flatten(xs)

我不确定,但我认为原因是

case x: List[_] => flatten(x) ::: flatten(xs)

版本的工作原理是它既可以进行检查,也可以进行投射。

答案 2 :(得分:1)

执行此操作时:

case x::xs =>

x绑定到列表的头部。因此,如果列表的类型为List[Any],那么当然头部的类型为Any(而不是List[Any]