开发者

Fixing a match clause warning by getting rid of a type parameter

i want to implement the following exhaustive match, but i can't figure out to remove the type parameter and thus the warning that it is erased:

sealed trait Q[+V]
case object QEmpty extends Q[Nothing]
sealed trait QNonEmpty[V] extends Q[V] {
  def foo: V
}
final class QLeaf[V](val foo: V) extends QNonEmpty[V]
final class QNode[V](val foo: V, var children: Array[Q[V]]) extends QNonEmpty[V]

def test[V](n: Q[V]): String = n match {
  case QEmpty          => "empty"
  case n: QNonEmpty[V] => n.foo.toString  // warning: type parameter V is erased
}

in my concrete case the body of the case n ma开发者_如何学Gotch is very large, and i do not want to add more match clauses so that i match instead against QLeaf and QNode (because in my concrete case there are more than two subclasses, also they are mutable and thus shouldn't be case classes). the resolved type needs to be QNonEmpty[V], it cannot be QNonEmpty[_].

Can I create an extractor for QNonEmpty which matches both QLeaf and QNode?


You can use existential types to match on a type with erased parameters:

type AnyNonEmpty = QNonEmpty[X] forSome { type X }

in match {
  case x: AnyNonEmpty => //...
}

An extractor could look like this:

object QNonEmpty {
  def unapply(in: QNonEmpty[_]): Option[Any] = Some(in.foo)
}

def test[ V ]( n: Q[ V ]) : String = n match {
   case QEmpty => "empty"
   case QNonEmpty(foo) => foo.toString
}

I don't think that you can write a typesafe extractor though, as in your example code the type parameter to the method is also erased. Maybe you should think about adding a fold method to your trait and rewrite your example like this:

sealed trait Q[ +V ] {
  def fold[A](e: => A, f: V => A): A = e
}

case object QEmpty extends Q[ Nothing ]

sealed trait QNonEmpty[ V ] extends Q[ V ] {
  def foo: V
  override def fold[A](e: => A, f: V => A) = f(foo)
}

// ...

def test[V](n: Q[V]) = n.fold("empty", _.toString)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜