在Scala中使用集合的麻烦类型



我尝试在不使用scala.reflect.classtag

的情况下在Scala中进行匹配
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)

我们不能这样做:

fc match {
  case Items(x) if x.isInstanceOf[Vector[Foo]]
}

因为:

警告:类型scala.collection.immutable.vector [foo](向量[foo]的基础[foo])中的非变量类型参数foo foo foo

将其消除,因此未选中。

和此:

fc match {
  case Items(x: Vector[Foo]) =>
}

,但我们可以做到这一点:

fc match {
  case Items(x@(_: Foo) +: _) => ...
  case Items(x@(_: Bar) +: _) => ...
}
bc match {
  case Items(x@(_: Foo) +: _) => ...
  case Items(x@(_: Bar) +: _) => ...
}

您可以看到,我们正在检查 - 是收集 vector或bar vector。

,我们有一些问题:

  1. 我们可以做矢量(foo(" 1"),bar(2)),这将与foo匹配。
  2. 我们仍然需要" val结果= x.asinstance [vector [bar]]" class cast for Result提取

有一些更美丽的方法吗?这样:

fc match {
  case Items(x: Vector[Foo]) => // result is type of Vector[Foo] already
}

您在这里做的事情从根本上只是不愉快的,所以我不确定以美丽的方式做到这一点是一件好事,但是对于它的价值来说是一件好事,无形的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))

…如果您尝试使用res3,这当然会扔ClassCastExceptionS。

不过这还不是更完整。

如果您想要使用隐式转换简单的东西。然后尝试!

implicit def VectorConversionI(items: Items): Vector[AnyRef] = items match { case x@Items(v) => v }
Example:
val fcVertor: Vector[AnyRef] = fc // Vector(Foo(a), Foo(b), Foo(c))
val bcVertor: Vector[AnyRef] = bc // Vector(Bar(1), Bar(2), Bar(3))

最新更新