Reputation: 83393
Frequently, I find myself doing pattern matching such as this
val foo: Foo = ...
foo match {
case bar: Bar => Some(bar)
case _ => None
}
I want to make this shorter.
val foo: Foo = ...
optInstance[Foo, Bar](foo)
Possibility 1 - direct translation
def optInstance[A, B <: A](a: A) = a match {
case b: B => Some(b)
case _ => None
}
// warning: abstract type pattern B is unchecked since it is eliminated by erasure
Possibility 2 - try-catch
def optInstance[A, B <: A](a: A) =
try {
Some(a.asInstanceOf[B])
} catch {
case e: ClassCastException => None
}
// no warnings
Possiblility 3 - if-else
def optInstance[A, B <: A](a: A) =
if(a.isInstanceOf[B]) {
Some(a.asInstanceOf[B])
} else {
None
}
// no warnings
None of them work. (Scala 2.11.2)
Is there a generic way of writing
foo match {
case bar: Bar => Some(bar)
case _ => None
}
(If not, is there at least a shorter way?)
Upvotes: 1
Views: 161
Reputation: 1838
Cleaner way using implicit value class:
implicit class AsOpt[A](val a: A) extends AnyVal {
def asOpt[B <: A : scala.reflect.ClassTag]: Option[B] = a match {
case b: B => Some(b)
case _ => None
}
}
Example:
val seq: Seq[Int] = Seq.empty
seq.asOpt[List[Int]] // Option[List[Int]] = Some(List())
seq.asOpt[Vector[Int]] // Option[Vector[Int]] = None
Upvotes: 2
Reputation: 1786
Just add an implicit ClassTag
for your first implementation:
import scala.reflect.ClassTag
def optInstance[A, B <: A : ClassTag](a: A): Option[B] = a match {
case b: B => Some(b)
case _ => None
}
Example:
sealed trait Foo
case object Bar extends Foo
case object Baz extends Foo
scala> optInstance[Foo, Bar.type](Bar)
res4: Option[Bar.type] = Some(Bar)
scala> optInstance[Foo, Bar.type](Baz)
res5: Option[Bar.type] = None
Upvotes: 4
Reputation: 55569
Without a generic function you can use Option
and collect
:
class Foo
class Bar extends Foo
class Baz extends Foo
scala> val foo: Foo = new Bar
scala> Some(foo).collect { case b: Bar => b }
res1: Option[Bar] = Some(Bar@483edb6b)
scala> val baz: Foo = new Baz
scala> Some(baz).collect { case b: Bar => b }
res3: Option[Bar] = None
Upvotes: 1