我有这个辅助功能:
def findByType[T: ClassTag](xs: Seq[Any]) =
xs.find(classTag[T].runtimeClass.isInstance).map(_.asInstanceOf[T])
我目前正在使用的:
val foo = findByType[Foo](xs)
val bar = findByType[Bar](xs)
val baz = findByType[Baz](xs)
然而,这里有一些重复;我喜欢什么(伪代码):
val List(foo, bar, baz) = List(Foo, Bar, Baz).map(t => findByType[t](xs))
我有什么选择?我可以按原样保留它,但如果有一些简单的东西可以干这个,我很乐意听到它。
答案 0 :(得分:8)
如果你绝对必须这样做,Shapeless可以使它更清洁,更安全:
import shapeless._
def findByType[T](xs: Seq[Any])(implicit t: Typeable[T]) =
xs.flatMap(t.cast).headOption
请注意,与您的实现不同,此实现不会对许多标准库的泛型类型给出错误答案:
scala> findByType[List[String]](Seq(List(1), List("a"), 'foo))
res3: Option[List[String]] = Some(List(a))
Vs以上。
scala> yourFindByType[List[String]](Seq(List(1), List("a"), 'foo))
res4: Option[List[String]] = Some(List(1))
(但是,您仍需要小心,因为这不适用于用户定义的泛型。)
它还可以让你做这样的好事:
trait Sifter[L <: HList] extends DepFn1[Seq[Any]] {
type Out <: HList
}
object Sifter {
type Aux[L <: HList, Out0 <: HList] = Sifter[L] { type Out = Out0 }
implicit def emptySized: Aux[HNil, HNil] = new Sifter[HNil] {
type Out = HNil
def apply(xs: Seq[Any]) = HNil
}
implicit def otherSized[H, T <: HList, OutT <: HList](implicit
typeable: Typeable[H],
sifter: Aux[T, OutT]
): Aux[H :: T, Seq[H] :: OutT] = new Sifter[H :: T] {
type Out = Seq[H] :: OutT
def apply(xs: Seq[Any]) = xs.flatMap(typeable.cast) :: sifter(xs)
}
def sift[L <: HList](xs: Seq[Any])(implicit sifter: Sifter[L]): sifter.Out =
sifter(xs)
}
然后:
scala> val myStuff: Seq[Any] = List(1, List('a', 'b'), "foo", 'bar)
myStuff: Seq[Any] = List(1, List(a, b), foo, 'bar)
scala> val myInts :: myCharLists :: myStrings :: HNil =
| Sifter.sift[Int :: List[Char] :: String :: HNil](myStuff)
myInts: Seq[Int] = List(1)
myCharLists: Seq[List[Char]] = List(List(a, b))
myStrings: Seq[String] = List(foo)
这基本上是你想要的类型安全版本。
答案 1 :(得分:2)
import scala.reflect.{ClassTag, classTag}
val List(foo, bar, baz) = List(classTag[Foo], classTag[Bar], classTag[Baz]).map(ct => findByType(xs)(ct))
当然,现在您丢失了类型信息 - foo
,bar
和baz
都会有类型Option[Any]
。