I'm trying to pattern match on a custom class with a typed parameter:
class Foo[A]
def isMyFoo[A: ClassTag](v: Any) = v match {
case mine: Foo[A] => "my foo"
case other: Foo[_] => "not my foo"
case _ => "not a foo"
}
That will not work; no matter the type of Foo, I will always get "my foo".
The only way I was able to make something like this work, is this:
class Foo[A](implicit t: ClassTag[A]) {
val tag = t
}
def isMyFoo[A: ClassTag](v: Any) = v match {
case foo: Foo[_] =>
if (foo.tag == classTag[A]) "my foo"
else "not my foo"
case _ => "not a foo"
}
Is there a more elegant way of doing so? Do I have to keep the ClassTag inside Foo?
Do I have to keep the ClassTag inside Foo?
Yes. The type parameter of Foo is erased at run-time, so all you know is that you have a Foo[_]. The only way around that is to save the type information using a ClassTag or TypeTag. If you're going to go this route, I would recommend using TypeTag, as you will be able to use more refined types. ClassTags still only work modulo type erasure.
For example, using a ClassTag, this is wrong:
scala> val fooListString = new Foo[List[String]]
fooListString: Foo[List[String]] = Foo@f202d6d
scala> isMyFoo[List[Int]](fooListString)
res4: String = my foo
But the following will work:
class Foo[A](implicit t: TypeTag[A]) {
val tag = t
}
def isMyFoo[A: TypeTag](v: Any) = v match {
case foo: Foo[_] =>
if (foo.tag.tpe =:= typeOf[A]) "my foo"
else "not my foo"
case _ => "not a foo"
}
scala> val fooListString = new Foo[List[String]]
fooListString: Foo[List[String]] = Foo@6af310c7
scala> isMyFoo[List[Int]](fooListString)
res5: String = not my foo
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