为什么我不能将 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 ++ bar
将 bar
的零个或一个元素附加到 acc
.
的元素
PS:一般应该使用模式匹配或高阶函数对列表进行操作,而不是head
和tail
.
我有以下递归方法:
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 ++ bar
将 bar
的零个或一个元素附加到 acc
.
PS:一般应该使用模式匹配或高阶函数对列表进行操作,而不是head
和tail
.