在不指定类型参数的情况下转换(或更确切地说:归因)集合类型

时间:2012-01-20 16:59:59

标签: scala collections type-parameter

说我List的{​​{1}}

Int

当然,Scala非常聪明,可以为我返回正确的类型。现在,考虑到,我对scala> val list = List(1, 2, 3, 4, 5) list: List[Int] = List(1, 2, 3, 4, 5) 的具体功能不感兴趣,而是想要更通用(超级)类型,比如List。显然,我可以指定它:

Traversable

但这意味着我还必须重复类型参数。

这不起作用

scala> val trav = list: Traversable[Int]
trav: Traversable[Int] = List(1, 2, 3, 4, 5)

这两个例子完全删除了类型参数信息

scala> list : Traversable
<console>:9: error: type Traversable takes type parameters
       list : Traversable
              ^

有没有办法获得scala> list : Traversable[T forSome {type T}] res2: Traversable[T forSome { type T }] = List(1, 2, 3, 4, 5) scala> list : Traversable[_] res3: Traversable[Any] = List(1, 2, 3, 4, 5) 而无需输入Traversable[Int]

6 个答案:

答案 0 :(得分:4)

你要求的基本上是多态函数;或者是高等级类型的函数。您可以在类型之间定义这样的映射* - &gt; *如下:

scala> trait ~>[F[_], G[_]] { def map[A](f: F[A]): G[A] }
defined trait $tilde$greater

你需要一个隐含的课程

scala> implicit object ListIsTrav extends (List ~> Traversable) { 
  | def map[A](l: List[A]): Traversable[A] = l 
  | }
defined module ListIsTrav

现在为* - &gt;形式的类型添加转换器*

scala> class Homomorphic[F[_], A](f: F[A]){  
  | def as[G[_]](implicit ev: F ~> G): G[A] = ev map f 
  | }
defined class Homomorphic

scala>  implicit def Type_Is_Homomorphic[F[_], A](f: F[A]) = new Homomorphic(f)
Type_Is_Homomorphic: [F[_], A](f: F[A])Homomorphic[F,A]

现在使用它:

scala> List(1, 2, 3).as[Traversable]
res0: Traversable[Int] = List(1, 2, 3)

这里的痛苦是List ~> Traversable排序的隐式实例的指数级爆炸。它在实践中并不可用。

答案 1 :(得分:2)

这有效,但是要避免输入Int有很多工作......也许有人可以基于此提出一个更简洁的技巧。

scala> def traversableId[T](t: Traversable[T])= t
traversableId: [T](t: Traversable[T])Traversable[T]

scala> traversableId(list)
res1: Traversable[Int] = List(1, 2, 3, 4, 5)

答案 2 :(得分:1)

虽然oxbow_lakes给出了关于如何针对任意组合解决此问题的great solution,但他鼓励我如何在TraversableList的超类型的情况下执行此操作1}}。 (但最初并未在问题中指明。)

class CastToSuperType[F[_], A](f: F[A]) {
  def as[G[_]](implicit ev: F[A] <:< G[A]): G[A] = f: G[A]
}

implicit def implCastToSuperType[F[_], A](f: F[A]) = new CastToSuperType(f)

scala> List(1, 2, 3).as[Traversable]
res0: Traversable[Int] = List(1, 2, 3)

我怀疑,具有任意数量类型参数的类型可能需要键入lambdas。

答案 3 :(得分:0)

写一个相应的方法:

def asTraversable[T](x: Traversable[T]) = x

asTraversable(x)

答案 4 :(得分:0)

集合类具有大多数广义特征的转换方法

scala> List(1,2,3).toTraversable
res0: Traversable[Int] = List(1, 2, 3)

scala> List(1,2,3).toIterable
res1: Iterable[Int] = List(1, 2, 3)

scala> List(1,2,3).toIndexedSeq
res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)

答案 5 :(得分:0)

在scala 2.10中它更加简单,因为引入了.to[Col[_]],它是scala.collection.TraversableLike的一部分

这是定义:

def to[Col[_]](implicit cbf : scala.collection.generic.CanBuildFrom[scala.Nothing, A, Col[A]]) : Col[A]

所以你基本上可以这样做:

scala> List(1, 2, 3, 4, 5).to[Vector]
res0: Vector[Int] = Vector(1, 2, 3, 4, 5)


scala> List(1, 2, 3, 4, 5).to[Set]
res1: Set[Int] = Set(5, 1, 2, 3, 4)