为什么我不能将Nil添加到列表中?

时间:2017-06-13 19:51:09

标签: scala scala-collections

我有以下递归方法:

def myMethod(foo: List[FooBar], acc: List[MyClass]): List[MyClass] {

   // ... some code ...

   myMethod(foo.tail, acc :+ getMyObject(foo.head).getOrElse(Nil))

}

方法getMyObject可选地返回MyClass的实例。不幸的是,我无法编译,因为我收到了这个错误:

[error]  found   : List[Product with Serializable]
[error]  required: List[MyClass]

此编译错误表示我无法将Nil附加到列表acc,因此我必须使用以下代码:

def myMethod(foo: List[FooBar], acc: List[MyClass]): List[MyClass] {

   // ... some code ...
   val bar = getMyObject(foo.head)
   myMethod(foo.tail, if (bar.isDefined) acc :+ bar.get else acc)

}

但是,我更喜欢第一种方法,因为它更简洁。为什么我不能将Nil附加到列表中?

3 个答案:

答案 0 :(得分:3)

:+获取n - elemnt列表和元素x并返回n+1 - 元素列表,其中最后一个元素为x。这意味着两件事:

  • 没有任何论据可以使用:+的正确操作数来获取相同大小的列表
  • :+的右操作数必须是列表的元素类型。

所以,只有当acc :+ Nil是一个列表列表时才可以acc进行acc ++ bar,即使那样它也不会做你想要的,因为它会在列表中添加一个空列表,而不是保留列表没有变化。

解决问题最简洁的方法是acc ++ bar。这使用连接而不是追加和工作,因为选项被视为0或1个元素的集合。因此bar会将acc的零个或一个元素附加到head的元素。

PS:您通常应该使用模式匹配或更高阶函数来操作列表,而不是tailfoo 2 foo 3 foo 4

答案 1 :(得分:1)

问题是追加操作:+获取非列表值并将其追加到列表中。问题是Nil和Myclass是不同的类型,因此结果列表采用满足MyClass和Nil的最具体类型。它们是完全不相关的类型,因此您最终将Product with Serializable作为常见的超类型。

要将一个元素或任何内容附加到列表中,请先将该元素包装到列表中。然后将您的单例列表或Nil与旧列表连接起来。

myMethod(foo.tail, acc ++ getMyObject(foo.head).map(x => List(x)).getOrElse(Nil))

答案 2 :(得分:0)

您使用的是错误的运算符,请使用++代替

myMethod(foo.tail, acc ++ getMyObject(foo.head).map(List(_)).getOrElse(Nil))

myMethod(foo.tail,  getMyObject(foo.head).map(acc :+ _).getOrElse(acc))