То, что вы здесь делаете, в принципе просто неприятно, так что я не уверен, что сделать это красиво - это хорошо, но за все это стоит, Бесформенный TypeCase
немного лучше:
case class Foo(name: String)
case class Bar(id: Int)
case class Items(items: Vector[AnyRef])
val foo = Vector(Foo("a"), Foo("b"), Foo("c"))
val bar = Vector(Bar(1), Bar(2), Bar(3))
val fc = Items(foo)
val bc = Items(bar)
val FooVector = shapeless.TypeCase[Vector[Foo]]
val BarVector = shapeless.TypeCase[Vector[Bar]]
А потом:
scala> fc match {
| case Items(FooVector(items)) => items
| case _ => Vector.empty
| }
res0: Vector[Foo] = Vector(Foo(a), Foo(b), Foo(c))
scala> bc match {
| case Items(FooVector(items)) => items
| case _ => Vector.empty
| }
res1: Vector[Foo] = Vector()
Обратите внимание, что хотя ClassTag
экземпляры также могут использоваться таким образом, они неделай, что хочешь:
scala> val FooVector = implicitly[scala.reflect.ClassTag[Vector[Foo]]]
FooVector: scala.reflect.ClassTag[Vector[Foo]] = scala.collection.immutable.Vector
scala> fc match {
| case Items(FooVector(items)) => items
| case _ => Vector.empty
| }
res2: Vector[Foo] = Vector(Foo(a), Foo(b), Foo(c))
scala> bc match {
| case Items(FooVector(items)) => items
| case _ => Vector.empty
| }
res3: Vector[Foo] = Vector(Bar(1), Bar(2), Bar(3))
… что, конечно, вызовет ClassCastException
с, если ты попытаешься использовать res3
.
Это действительно нехорошо,хотя - проверка типов во время выполнения подрывает параметричность, делает ваш код менее надежным и т. д. Стирание типов - хорошая вещь, и единственная проблема со стиранием типов в JVM состоит в том, что он не является более полным.