我试图解决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的某些部分,我不明白?
谢谢!
答案 0 :(得分:3)
在您的代码中,x
是List[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]
)