如果我想缩小某个特定类型的所有元素Iterable[A]
(例如String
),我可以这样做:
as filter { _.isInstanceOf[String] }
但是,显然希望使用作为Iterable[String]
这可以通过map
完成:
as filter { _.isInstanceOf[String] } map { _.asInstanceOf[String] }
哪个很难看。当然,我可以使用flatMap
代替:
as flatMap[String] { a =>
if (a.isInstanceOf[String])
Some(a.asInstanceOf[String])
else
None
}
但我不确定这是否更具可读性!我编写了一个函数narrow
,可以通过implicit
次转换使用:
as.narrow(classOf[String])
但我想知道是否有一个我忽略的更好的内置机制。特别是因为能够将List[A]
缩小到List[String]
,而不是像我的函数那样缩小到Iterable[String]
会很好。
答案 0 :(得分:8)
isInstanceOf
/ asInstanceOf
的Scala语法糖是模式匹配:
as flatMap { case x: String => Some(x); case _ => None }
因为它使用flatMap
,所以它通常应该返回您必须开始的相同集合。
在Scala 2.8上,有一个实验函数可以在对象PartialFunction中定义这种模式。所以,在Scala 2.8上你可以做到:
as flatMap (PartialFunction.condOpt(_ : Any) { case x: String => x })
哪个看起来更大,主要是因为我没有先导入该功能。但是,再一次,在Scala 2.8上有更直接的方法:
as collect { case x: String => x }
答案 1 :(得分:3)
记录中,这是narrow
的完整实现。与问题中给出的签名不同,它使用隐式Manifest
来避免某些字符:
implicit def itrToNarrowSyntax[A](itr: Iterable[A]) = new {
def narrow[B](implicit m: Manifest[B]) = {
itr flatMap { x =>
if (Manifest.singleType(x) <:< m)
Some(x)
else
None
}
}
}
val res = List("daniel", true, 42, "spiewak").narrow[String]
res == Iterable("daniel", "spiewak")
不幸的是,缩小到特定类型(例如List[String]
)而不是Iterable[String]
有点困难。可以使用Scala 2.8.0中的新集合API通过利用更高类型来完成它,但不能在当前框架中完成。
答案 2 :(得分:1)
您可以在将来使用:
for(a :Type <- itr) yield a
但它现在不起作用。 有关更多信息,请转到以下链接: http://lampsvn.epfl.ch/trac/scala/ticket/1089 http://lampsvn.epfl.ch/trac/scala/ticket/900
答案 3 :(得分:1)
保持形状:我现在有点匆忙,所以我要离开那里的演员,但我很确定它可以被淘汰。这适用于主干:
import reflect.Manifest
import collection.Traversable
import collection.generic.CanBuildFrom
import collection.mutable.ListBuffer
object narrow {
class Narrower[T, CC[X] <: Traversable[X]](coll: CC[T])(implicit m1: Manifest[CC[T]], bf: CanBuildFrom[CC[T], T, CC[T]]) {
def narrow[B: Manifest]: CC[B] = {
val builder = bf(coll)
def isB(x: T): Option[T] = if (Manifest.singleType(x) <:< manifest[B]) Some(x) else None
coll flatMap isB foreach (builder += _)
builder mapResult (_.asInstanceOf[CC[B]]) result
}
}
implicit def toNarrow[T, CC[X] <: Traversable[X]](coll: CC[T])(implicit m1: Manifest[CC[T]], bf: CanBuildFrom[CC[T], T, CC[T]]) =
new Narrower[T,CC](coll)
def main(args: Array[String]): Unit = {
println(Set("abc", 5, 5.5f, "def").narrow[String])
println(List("abc", 5, 5.5f, "def").narrow[String])
}
}
运行它:
Set(abc, def)
List(abc, def)