1

我试图解决99 个 Scala 问题中的第 7 个问题,但在找出List可以包含任何类型的 a 类型时遇到了一些困难。所以我看了看答案,发现它是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[_]]会产生相同的编译错误。

在谷歌搜索和咨询这个解决方案之后,我实现了这个:

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 的某些部分?

谢谢!

4

3 回答 3

3

在您的代码中,x是 a 的头部List[Any]:它是 a Any,因此您会收到错误消息。您需要将其转换为 a 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)
}
于 2013-07-25T13:29:09.970 回答
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)

版本的作品是它既做检查又做演员。

于 2013-07-25T13:26:07.240 回答
1

当你这样做时:

case x::xs =>

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

于 2013-07-25T13:29:07.490 回答