If I want to narrow, say, an Iterable[A]
for all elements of a particular type (e.g. String
) I can do:
as filter { _.isInstanceOf[String] }
However, it's obviously desirable to use this as an Iterable[String]
which can be done via a map
:
as filter { _.isInstanceOf[String] } map { _.asInstanceOf[String] }
Which is pretty ugly. Of course I could use flatMap
instead:
as flatMap[String] { a =>
if (a.isInstanceOf[String])
Some(a.asInstanceOf[String])
else
None
}
But I'm not sure that this is any more readable! I have written a function, narrow
, which can be used via implicit
conversions:
as.narrow(classOf[String])
But I was wondering if there was a better built-in mechanism which I have overlooked. Particularly as it would be nice to be able to narrow a List[A]
to a List[String]
, rather than to an Iterable[String]
as it will be with my function.
The Scala syntax sugar for isInstanceOf
/ asInstanceOf
is pattern matching:
as flatMap { case x: String => Some(x); case _ => None }
Because that uses flatMap
, it should usually return the same collection you had to begin with.
On Scala 2.8, there's an experimental function that does that kind of pattern, defined inside the object PartialFunction. So, on Scala 2.8 you can do:
as flatMap (PartialFunction.condOpt(_ : Any) { case x: String => x })
Which looks bigger mostly because I did not import that function first. But, then again, on Scala 2.8 there's a more direct way to do it:
as collect { case x: String => x }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With