7

我是 Scala 的新手,我对类型系统有疑问。

flatten 方法适用于嵌套集合,因此如果我有一个 List 列表,它将把它展平为一个 List。但是在已经平坦的集合上调用 flatten 是没有意义的。果然,Scala 类型检查器会将其标记为错误。

List(List(1,2,3),List(4,5,6)).flatten // produces List(1,2,3,4,5,6)
List(1,2,3,4).flatten  // type error

我知道这在某种程度上依赖于隐式参数来展平。但是我不知道隐式值来自哪里以及它是如何用来断言调用 flatten 的对象的类型的。另外,为什么 List.flatten 的 scaladocs 中没有显示隐式参数?

4

2 回答 2

4

要了解它是如何工作的,我们需要看一下 flatten 的类型签名:

def flatten[B](implicit asTraversable: (A) ⇒ GenTraversableOnce[B]): List[B]

A是列表的元素类型,B是每个元素的元素类型。为了让 flatten 工作,必须有一个从元素类型到 a 的隐式转换GenTraversableOnce[B]。这仅适用于集合或您实现自己的隐式转换的情况。例如,您可以为对定义一个:

implicit def pairToList[A](p:(A,A)) = List(p._1, p._2)

List(1->2,2->3).flatten //compiles! List(1,2,2,3)
于 2012-10-24T14:38:19.433 回答
1

诀窍是隐式见证,确保列表中的元素是可遍历的。这是flatten取自GenericTraversableTemplate的(稍微简化的)签名:

def flatten[B](implicit asTraversable: A => TraversableOnce[B])
              : GenTraversable[B] =

在您的情况下,无法找到 type 元素的见证,因此编译器拒绝Int调用 of 。flatten


如果您想让您的示例编译,您可以使用以下隐式定义:

implicit def singleToList[A](a: A) = List(a)

(作为旁注:我认为这种隐式非常危险,因为它的适用性非常普遍,这可能会导致令人不快的意外,因为编译器可能会在您不知道的情况下在各个地方注入调用。)

于 2012-10-24T14:40:18.093 回答