我想在一些Iterable中找到一些符合某些给定类型的元素,并验证以该类型为参数的谓词。
我使用命令式编程编写了这个方法,这似乎符合我的期望。有没有办法用更“scalaesque”的方式写这个?
def findMatch[T](it: Iterable[_], clazz: Class[T], pred: T => Boolean): Option[T] = {
val itr = it.iterator
var res: Option[T] = None
while (res.isEmpty && itr.hasNext) {
val e = itr.next()
if (clazz.isInstance(e) && pred(clazz.cast(e))) {
res = Some(clazz.cast(e))
}
}
res
}
答案 0 :(得分:17)
如果您想要collect
,然后find
,则可以使用map
。
scala> val it: Iterable[Any] = List(1,2,3,"4")
it: Iterable[Any] = List(1, 2, 3, 4)
scala> it.view.collect{case s: String => s}.headOption
res1: Option[String] = Some(4)
答案 1 :(得分:1)
您可以使用现有类型X forSome{typeX}
,而不是使用_
作为类型参数。然后,这将使您能够使用提到的find方法编写它,并在Option类型上使用map方法:
def findMatch[T](it: Iterable[X forSome {type X}], clazz: Class[T], pred: T => Boolean): Option[T] = {
it.find{ e => clazz.isInstance(e) && pred(clazz.cast(e))}.map{clazz.cast(_)}
}
答案 2 :(得分:1)
如果将问题划分为子问题,则很容易找到更惯用的版本。 你想要
T
Iterable[Any]
的所有实例
T
以使编译器满意首先,您可以在filter
上轻松使用Iterator
方法。你有
it.iterator.filter(x => clazz.isInstance(x))
会返回仅包含Iterator[Any]
的{{1}}。现在让我们说服编译器:
T
好的,现在你有一个it.iterator.filter(x => clazz.isInstance(x)).map(x => x.asInstanceOf[T])
- 所以你只需要找到第一个满足谓词的元素:
Iterator[T]
答案 3 :(得分:0)
您可以使用Iterable
的{{1}}方法并与警卫进行模式匹配:
find
有关模式匹配的介绍,请参阅: http://programming-scala.labs.oreilly.com/ch03.html