我有以下递归方法:
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
附加到列表中?
答案 0 :(得分:3)
:+
获取n
- elemnt列表和元素x
并返回n+1
- 元素列表,其中最后一个元素为x
。这意味着两件事:
:+
的正确操作数来获取相同大小的列表:+
的右操作数必须是列表的元素类型。所以,只有当acc :+ Nil
是一个列表列表时才可以acc
进行acc ++ bar
,即使那样它也不会做你想要的,因为它会在列表中添加一个空列表,而不是保留列表没有变化。
解决问题最简洁的方法是acc ++ bar
。这使用连接而不是追加和工作,因为选项被视为0或1个元素的集合。因此bar
会将acc
的零个或一个元素附加到head
的元素。
PS:您通常应该使用模式匹配或更高阶函数来操作列表,而不是tail
和foo 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))