2014-03-05 42 views
2

,我有以下形式的函數:在Scala中編寫TraversableOnce的通用函數?

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數組和TraversableOnce之間的關係?直覺上來說,我認爲上述方法應該可行,因爲一個數組事實上至少可以遍歷一次。

在實踐中,最簡單的方法是使數組,集合,流和任何其他可以遍歷一次的數據結構工作嗎?

回答

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) 
+0

是的!這正是我想要做的。謝謝。 – joshuaar

3

首先,您的代碼不起作用,因爲類型推斷很困惑。明確指定類型參數:

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

數組[T]是Scala對Java的T []的表示。數組不是Scala Collection/Traversable。它被隱式轉換爲一個,但它不是一個Traversable的實例。

要查看斯卡拉集合及其relatioship的一個很好的概述,檢查: 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) 

本人來說,我通常使用的Iterable [T]如果只我需要做的就是簡單地貫穿所有元素,但一般來說這不是最優的。下面是一些關於它的推理: Scala: What is the difference between Traversable and Iterable traits in Scala collections?

+0

實際上,如果將第二個數組轉換爲可遍歷的,則代碼可以正常工作。這個問題似乎是在將第二個數組封裝在Option中。另外我想避免指定double,float等爲通用。我編輯來展示我的意思。 – joshuaar

+0

我已經更新了我的答案。數組是一個非常特殊的結構。你可以說它不是Scala類型,而是Java。如果可以,請使用List。 –

+0

啊,你是對的。列表工作得很好。它是一個恥辱,因爲我用這種方式編寫它的唯一原因是它適用於數組,列表,流或任何其他組合。 – joshuaar

相關問題