TL; DR
使用此斯卡拉2.9.x:
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) : Seq[T] = {
seq.collect {
case t if m.erasure.isInstance(t) => t.asInstanceOf[T]
}
}
scala> typeOnly[String](List(1,2,"3",4))
res1: Seq[String] = List(3)
這對於Scala的2.10.x:
def typeOnly[T](seq : Seq[Any])(implicit tag : scala.reflect.ClassTag[T]) = {
seq.collect {
case t if tag.runtimeClass.isInstance(t) => t.asInstanceOf[T]
}
}
作爲Seq
被定義爲trait Seq[+A]
(關鍵是+
),任何Seq[S]
也是Seq[Any]
。另一方面,正如已經說過的那樣,當函數被編譯時T被「忘記」了,所以你不能直接使用它。你必須通過T類作爲參數,如何。
def typeOnly[T](seq : Seq[Any], c : Class[T]) : Seq[T] = {
seq.flatMap {
case t if c.isInstance(t) => Some(t.asInstanceOf[T])
case _ => None
}
}
在Scala中,APPART從Class[T]
,也有Manifest[T]
,這是更強大一點,作爲一個結果,更地道。特別是,它有一個方法erasure
,它返回一個Class[T]
。使用它,你可以去寫這樣的功能:
def typeOnly[T](seq : Seq[Any], m : Manifest[T]) : Seq[T] = {
seq.flatMap {
case t if m.erasure.isInstance(t) => Some(t.asInstanceOf[T])
case _ => None
}
}
看來我們沒有獲得任何東西。但是,如果您很好地詢問編譯器(使用implicit
),則在調用該函數時它會通過Manifest
。
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) : Seq[T] = {
seq.flatMap {
case t if m.erasure.isInstance(t) => Some(t.asInstanceOf[T])
case _ => None
}
}
例子:
scala> typeOnly[java.lang.Integer](List(1,2,"3",4))
res2: Seq[java.lang.Integer] = List(1, 2, 4)
scala> typeOnly[String](List(1,2,"3",4))
res3: Seq[String] = List(3)
scala> typeOnly[java.lang.Double](List(1,2,"3",4))
res4: Seq[java.lang.Double] = List()
有更多的選擇,其中一些還更地道。你可以,例如, 使用collect
與部分定義的函數:
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) : Seq[T] = {
seq.collect {
case t if m.erasure.isInstance(t) => t.asInstanceOf[T]
}
}
警告:前者的例子合作在斯卡拉2.9.3及以下。如果您正在開發斯卡拉2.10.x,Manifest#erasure
已被棄用。使用runtimeClass
代替:
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) = {
seq.collect {
case t if m.runtimeClass.isInstance(t) => t.asInstanceOf[T]
}
}
由於艙單很快就會過時過(見下面的評論),你應該考慮使用ClassTag。
def typeOnly[T](seq : Seq[Any])(implicit tag : scala.reflect.ClassTag[T]) = {
seq.collect {
case t if tag.runtimeClass.isInstance(t) => t.asInstanceOf[T]
}
}
編譯** **可以推斷出一個事實,即'列表(1,「2」,3「 4「)'是'Seq [Any]',但它不能忍受你忽略忘記指定第二種類型的想法。請注意,您的匹配是無用的,因爲Seq類型在運行時被刪除。 –
嗯,你說得對。是否有可能用類類型重寫此方法? –
如果你願意成爲類型安全的,你可以考慮使用'HLists'而不是'Lists'。 [無形庫](https://github.com/milessabin/shapeless/)的實現有一個方法('filter'),它可以做你想做的。 [實施例](https://github.com/milessabin/shapeless/blob/master/core/src/test/scala/shapeless/hlist.scala#L604-L632)。 – folone