4

例如,如果我想缩小Iterable[A]特定类型(例如String)的所有元素的范围,我可以这样做:

as filter { _.isInstanceOf[String] }

但是,显然希望将用作Iterable[String]可以通过 a 完成的操作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])

但我想知道是否有一个我忽略的更好的内置机制。特别是因为能够将 a 缩小List[A]到 a List[String],而不是Iterable[String]像我的函数那样缩小到 a 会很好。

4

4 回答 4

8

isInstanceOf/的 Scala 语法糖asInstanceOf是模式匹配:

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 }
于 2009-09-28T18:16:14.210 回答
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 来完成,但不能在当前框架中完成。

于 2009-09-28T19:38:42.287 回答
1

您将来可能会使用:

for(a :Type <- itr) yield a

但它现在不起作用。如需更多信息,请访问以下链接: http://lampsvn.epfl.ch/trac/scala/ticket/1089 http://lampsvn.epfl.ch/trac/scala/ticket/900

于 2009-09-30T04:02:26.957 回答
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)
于 2009-10-29T16:14:29.837 回答