Scala 基于包含的类型提取集合的成员(如果该成员在该类型上是协变的)

Scala 基于包含的类型提取集合的成员(如果该成员在该类型上是协变的),scala,covariance,Scala,Covariance,我有一个案例类,它的一个成员变量的类型是协变的,它被限制为一个特定的类型: case class MyCount[+T <: Identifier]( id: T, count: Long, ) 给定一组MyCount[Identifier]我想: 提取所有MyCount[IdentifierFoo] 使生成的集合具有类型SomeCollection[MyCount[IdentifierFoo]] (对我来说)显而易见的做法如下: src.collect { case count

我有一个案例类,它的一个成员变量的类型是协变的,它被限制为一个特定的类型:

case class MyCount[+T <: Identifier](
  id: T,
  count: Long,
)
给定一组
MyCount[Identifier]
我想:

  • 提取所有
    MyCount[IdentifierFoo]
  • 使生成的集合具有类型
    SomeCollection[MyCount[IdentifierFoo]]
  • (对我来说)显而易见的做法如下:

    src.collect { case countFoo: MyCount[IdentifierFoo] => countFoo }
    
    src.collect { case countFoo: MyCount[IdentifierFoo](_: 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] => countFoo }
    
    src.collect { case countFoo: MyCount[IdentifierFoo](_: IdentifierFoo, _) => countFoo }
    

    …但这在Scala 2.10中似乎是无效的,这正是我必须遵守的。有没有更好的方法来完成我想做的事情?

    既然你有
    IdentifierFoo
    IdentifierBar
    的提取器,并且知道它们的结构,你可以使用它们。通过使用提取器,您不会仅在类型上进行匹配,因此我们可以绕过类型擦除

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

    密封特征标识符
    案例类标识符foo(id:Int)扩展了标识符
    案例类标识符bar(id:Int)扩展了标识符
    案例类MyCount[+T list.collect{case countFoo@MyCount(IdentifierFoo(_),_)=>countFoo}
    res142:List[MyCount[具有可序列化标识符的产品]]=List(MyCount(IdentifierFoo(1,2))
    scala>list.collect{case countFoo@MyCount(IdentifierBar(_),_)=>countFoo}
    res143:List[MyCount[具有可序列化标识符的产品]]=List(MyCount(标识符栏(2),3),MyCount(标识符栏(3,4))
    
    正如@m-z所提到的,在结构上匹配比在类型上匹配更好,但是如果希望结果是类型
    列表[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))
    
    选中此项: