当某个集合的成员在所包含的类型上协变时,基于该类型提取该集合的成员



我在其成员变量之一的类型上有一个case类协变,它被约束为特定类型:

case class MyCount[+T <: Identifier](
  id: T,
  count: Long,
)

标识符是一个封闭的特性,有两个具体的实现,尽管我认为这对问题不重要:

sealed trait Identifier
case class IdentifierFoo(...) implements Identifier
case class IdentifierBar(...) implements Identifier

给定MyCount[Identifier]的集合,我想:

  1. 提取所有MyCount[IdentifierFoo]
  2. 使生成的集合具有类型SomeCollection[MyCount[IdentifierFoo]]

(对我来说)显而易见的方法如下:

src.collect { case countFoo: MyCount[IdentifierFoo] => countFoo }

然而,这失败了,因为由于类型擦除,无法在运行时准确检查Count的类型:结果(错误地)得到了所有Count s。我最终做了一件看起来很麻烦的事情:

src.collect { count => 
  count.id match { case IdentifierFoo => { 
    count match {case countFoo: MyCount[IdentifierFoo] => countFoo }
} } }

这很管用,但很难看。我还试着将整个计数匹配如下:

src.collect { case countFoo: MyCount[IdentifierFoo](_: IdentifierFoo, _) => countFoo }

但这在Scala2.10中似乎是无效的,这正是我所要做的。有没有更好的方法来做我想做的事情?

正如@m-z所提到的,与类型相比,您更擅长在结构上进行匹配,但如果您希望结果为List[MyCount[IdentifierFoo]]类型,则必须强制转换值:

val list: List[MyCount[Identifier]] = List(MyCount(IdentifierFoo(1), 2), MyCount(IdentifierBar(2), 3), MyCount(IdentifierBar(3), 4))
 list.collect{ case countFoo @ MyCount(_ : IdentifierFoo,_) => countFoo.asInstanceOf[MyCount[IdentifierFoo]]}  
 res0: List[MyCount[IdentifierFoo]] = List(MyCount(IdentifierFoo(1),2))
 list.collect{ case countFoo @ MyCount(_ : IdentifierBar,_) =>  countFoo.asInstanceOf[MyCount[IdentifierBar]]} 
 res1: List[MyCount[IdentifierBar]] = List(MyCount(IdentifierBar(2),3), MyCount(IdentifierBar(3),4))

因为您有IdentifierFooIdentifierBar的提取器,并且知道它们的结构,所以可以使用它们。通过使用提取器,您不能仅根据类型进行匹配,因此我们可以绕过类型擦除。

list.collect { case countFoo @ MyCount(IdentifierFoo(_), _) => countFoo }

例如:

sealed trait Identifier
case class IdentifierFoo(id: Int) extends Identifier
case class IdentifierBar(id: Int) extends Identifier
case class MyCount[+T <: Identifier](id: T, count: Long)
val list = List(MyCount(IdentifierFoo(1), 2), MyCount(IdentifierBar(2), 3), MyCount(IdentifierBar(3), 4))
scala> list.collect { case countFoo @ MyCount(IdentifierFoo(_), _) => countFoo }
res142: List[MyCount[Product with Serializable with Identifier]] = List(MyCount(IdentifierFoo(1),2))
scala> list.collect { case countFoo @ MyCount(IdentifierBar(_), _) => countFoo }
res143: List[MyCount[Product with Serializable with Identifier]] = List(MyCount(IdentifierBar(2),3), MyCount(IdentifierBar(3),4))

相关内容

  • 没有找到相关文章

最新更新