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

Why can't I append Nil to a list?

我有以下递归方法:

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

   // ... some code ...

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

}

方法 getMyObject returns 可选 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 附加到列表?

您使用了错误的运算符,请改用 ++

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

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

问题是追加操作 :+ 接受一个非列表值并将其追加到列表中。问题是 Nil 和 Myclass 是不同的类型,因此结果列表采用同时满足 MyClass 和 Nil 的最具体的类型。它们是完全不相关的类型,所以你最终得到 Product with Serializable 作为普通超类型。

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

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

:+ 接受一个 n 元素列表和一个元素 x 和 returns 一个 n+1 元素列表,其中最后一个元素是 x。这意味着两件事:

  • 没有参数可以用作 :+ 的右操作数来获得相同大小的列表
  • :+的右操作数需要是列表的元素类型。

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


解决您的问题最简洁的方法是acc ++ bar。这使用连接而不是追加并且有效,因为选项被视为 0 或 1 元素的集合。因此 acc ++ barbar 的零个或一个元素附加到 acc.

的元素

PS:一般应该使用模式匹配或高阶函数对列表进行操作,而不是headtail.