在Scala中编写TraversableOnce的通用函数?

时间:2014-03-05 04:37:00

标签: scala

我有以下形式的功能:

def tTest[T](it1 : TraversableOnce[T], it2 : Option[TraversableOnce[T]] =  None)
  (implicit frac: Fractional[T]) = {
...
}

我的意图是这样称呼:

tTest( Array(1.0,2,3,4), Option(Array(1.0,8,7)) )

有时也喜欢:

tTest( Array(1.0,2,3,4) )

第二个工作正常,但当我尝试拨打第一个时,我得到以下内容:

scala:14: type mismatch;
found   : Option[Array[Double]]
required: Option[TraversableOnce[?]]

[编辑]此代码正常工作:

tTest( Array(1.0,2,3,4), Option(Array(1.0,8,7).toTraversable) )

我的问题是:Scala中Array和TraversableOnce之间的关系是什么?直觉上,我认为上面应该可行,因为数组实际上至少可以遍历一次。

实际上,对于Arrays,Sets,Streams以及可遍历一次的任何其他数据结构,最简单的方法是什么?

2 个答案:

答案 0 :(得分:3)

首先,您的代码不起作用,因为类型推断混淆了。明确指定类型参数:

tTest[Double]( Array(1.0,2,3,4), Option(Array(1.0,8,7)) )

Array [T]是Scala代表Java的T []。 Array不是Scala Collection / Traversable。它被隐式转换为1,但它不是Traversable的实例。

要查看Scala集合及其关系的精彩概述,请检查以下内容: http://docs.scala-lang.org/overviews/collections/overview.html

您也可以使用隐式转换:

import scala.language.implicitConversions
implicit def conv[T](a: Option[Array[T]]): Option[Traversable[T]] = a.map(_.toTraversable)

Personaly我通常使用Iterable [T]如果我唯一需要做的就是简单地遍历所有元素,但它一般不是最佳的。以下是一些推理: Scala: What is the difference between Traversable and Iterable traits in Scala collections?

答案 1 :(得分:1)

这是另一种解决方案:

scala> def tTest[T, C[_]](it1: C[T], it2: Option[C[T]] = None)
     |                   (implicit frac: math.Fractional[T], ev: C[T] => TraversableOnce[T]): TraversableOnce[T] = ev(it1)
tTest: [T, C[_]](it1: C[T], it2: Option[C[T]])(implicit frac: scala.math.Fractional[T], implicit ev: C[T] => scala.collection.TraversableOnce[T])scala.collection.TraversableOnce[T]

scala> tTest( Array(1.0,2,3,4), Option(Array(1.0,8,7)) )
res0: scala.collection.TraversableOnce[Double] = [D(1.0, 2.0, 3.0, 4.0)

scala> tTest( Array(1.0,2,3,4) )
res1: scala.collection.TraversableOnce[Double] = [D(1.0, 2.0, 3.0, 4.0)

编辑以上解决方案不适用于以下情况:

scala> tTest(Array(1.2), Option(List(2.0)))
<console>:9: error: inferred kinds of the type arguments (Double,Object) do not conform to the expected kinds of the type parameters (type T,type C).
Object's type parameters do not match type C's expected parameters:
class Object has no type parameters, but type C has one
              tTest(Array(1.2), Option(List(2.0)))
              ^
<console>:9: error: type mismatch;
 found   : Array[Double]
 required: C[T]
              tTest(Array(1.2), Option(List(2.0)))

所以,这是一个更复杂和更灵活的方法:

scala> import math.Fractional
import math.Fractional

scala> import collection.{TraversableOnce => TO}
import collection.{TraversableOnce=>TO}

scala> def tTest2[T, C1[_], C2[_]](i1: C1[T], i2: Option[C2[T]])
     |                            (implicit fc: Fractional[T],
     |                                      e1: C1[T] => TO[T],
     |                                      e2: C2[T] => TO[T]): TO[T] = e1(i1)


scala> tTest2(Array(1.2, 2.3), Option(List(2.3)))
res5: scala.collection.TraversableOnce[Double] = [D(1.2, 2.3)

scala> tTest2(Array(1.2, 2.3), Option(Array(2.3)))
res6: scala.collection.TraversableOnce[Double] = [D(1.2, 2.3)