【发布时间】:2015-09-15 14:45:15
【问题描述】:
这似乎是一个简单的问题,我以前肯定有人问过,但找不到我要找的东西。
如何编写一个将集合作为参数(或任何可被视为集合)的函数,对其执行一些操作,并返回相同类型的集合?
例如:
scala> def foo[Repr <% Traversable[String]](repr: Repr) = repr.map(_.size)
foo: [Repr](repr: Repr)(implicit evidence$1: Repr => Traversable[String])Traversable[Int]
这适用于某些收藏:
scala> foo(Vector("Hello","World"))
res0: Traversable[Int] = Vector(5, 5)
但当我尝试其他收藏时令人惊讶(例如Option):
scala> foo(Some("HelloWorld"))
res1: Traversable[Int] = List(10)
一个小问题是返回类型Traversable,理想情况下它应该是给方法的任何类型。更大的问题是实际的实现类型:Option 变成了List。
当在类(行为类似于集合)上尝试但没有隐含的范围时,情况会变得更糟。例如:Try:
scala> import scala.util._
import scala.util._
scala> foo(Success("HelloWorld"))
<console>:12: error: No implicit view available from scala.util.Success[String] => Traversable[String].
foo(Success("HelloWorld"))
^
那么,有没有办法编写一个通用函数,当给定一个“类似集合”的参数时,可以对其元素进行操作并返回正确的类型?
理想情况下,我想在任何东西上使用它(甚至是 Future 和 Try),但对于我的特定用途,我可以只使用真正的集合和 Option。
编辑:
为了说明一个可能的解决方案,(这迫使我复制和粘贴代码,因此,这不是我想要的)是简单地编写两个没有视图边界的函数:
scala> :paste
// Entering paste mode (ctrl-D to finish)
def foo[Repr <: Traversable[String]](repr: Repr) = repr.map(_.size)
def foo(repr: Option[String]) = repr.map(_.size)
// Exiting paste mode, now interpreting.
foo: [Repr <: Traversable[String]](repr: Repr)Traversable[Int] <and> (repr: Option[String])Option[Int]
foo: [Repr <: Traversable[String]](repr: Repr)Traversable[Int] <and> (repr: Option[String])Option[Int]
scala> foo(Vector("bar"))
res2: Traversable[Int] = Vector(3)
scala> foo(Some("bar"))
res3: Option[Int] = Some(3)
【问题讨论】:
-
并不是所有的集合都可以支持所有可能的操作,所以一般来说你不能写一些东西来支持任意操作。您需要的操作种类是否有任何限制?
-
具体来说,我只有一个
map调用。但是如果有办法让它更通用并允许其他操作,如flatMap或filter,我想知道如何。 -
我:我真的不知道你在追求什么。同样,并非所有集合都支持所有操作。所以你需要以某种方式限制类型。您是否要求能够定义一个适用于所有支持
flatMap的集合类型的操作?还是别的什么? -
也就是说,“任何可以被视为集合”中的“被视为集合”是什么意思?
-
您认为哪种实现返回类型适合 foo(Option[T]) ?
标签: scala collections