2013-06-03 93 views
0

給定一個包含變量類型項目的Scala集合,我可以按類型進行過濾。如何參數化按類型過濾Scala對象的集合?

trait X 
case class Y(y:Int) extends X 
case class Z(z:Int) extends X 
val l = List(Y(1), Y(2), Z(3), Z(4)) 
l.collect{case e: Y=>e} // returns List[Y] = List(Y(1), Y(2)) 
l.collect{case e: Z=>e} // returns List[Z] = List(Z(3), Z(4)) 

我需要參數化過濾。最後一行返回error: not found: type f。在這個case語法中不允許Scala類型的參數化。

是否有Scala-esque的方式來參數化這個過濾操作? (也許使用collect函數以外的東西。)是否需要反射?

回答

1

val f = YY不是一個類型,而是伴侶對象。

你可以使用類型是這樣的:

type T = Y 
l.collect{case e: T=>e} // returns List[Y] = List(Y(1), Y(2)) 

或者你可以使用伴侶的對象,但只針對特定的參數計算:

val t = Y 
l.collect{case e @ t(_)=>e} // returns List[Y] = List(Y(1), Y(2)) 

在這種情況下,你應該使用e @ t(_, _)case class Y(y1:Int, y2:Int)e @ t(_, _, _)case class Y(y1:Int, y2:Int, y3:Int)等。

1

您不能類型本身分配給VAL,但你可以參數化使用的方法類型參數:

def filterOnType[T : ClassTag](c: Traversable[Any]): Traversable[T] = { 
    val tag = implicitly[ClassTag[T]]; 
    c.collect { case tag(t) => t } 
} 

ClassTag作爲一種方法來保持,在運行時,類信息有關T。否則T將被刪除,並且.collect { case t: T => t }將與.collect { case t: AnyRef => t }相同。

scala> filterOnType[Y](l) 
res7: Traversable[Y] = List(Y(1), Y(2)) 

scala> filterOnType[Z](l) 
res8: Traversable[Z] = List(Z(3), Z(4)) 

如果你絕對需要保持類型的一些代表性的VAL,然後保持ClassTag將在這裏工作。 val將不得不暗示由filterOnlyType拾取,或者您可以直接給它:filterOnlyType[X](l)(myClassTagForX)