Scala:基于类型参数筛选集合

Scala:基于类型参数筛选集合,scala,collections,type-erasure,Scala,Collections,Type Erasure,假设我可以控制这两个类,并且需要协变过滤,那么基于对象的类型参数过滤对象集合的最佳方法是什么 以下是一些无法正常工作的代码: trait Foo case class Foo1() extends Foo trait ReadableFoo extends Foo {def field: Int} case class Foo2(field: Int, flag: Boolean) extends ReadableFoo case class Foo3(field: Int, name: Str

假设我可以控制这两个类,并且需要协变过滤,那么基于对象的类型参数过滤对象集合的最佳方法是什么

以下是一些无法正常工作的代码:

trait Foo
case class Foo1() extends Foo
trait ReadableFoo extends Foo {def field: Int}
case class Foo2(field: Int, flag: Boolean) extends ReadableFoo
case class Foo3(field: Int, name: String) extends ReadableFoo

case class Bar[+F <: Foo](foo: F)

val seq = Seq(
  Bar[Foo1](Foo1()),
  Bar[Foo2](Foo2(1,true)), 
  Bar[Foo3](Foo3(1,"Fooz"))
)

// Should keep one
val first = seq collect {case x: Bar[Foo2] => x}

// Should keep two
val both = seq collect {case x: Bar[ReadableFoo] => x}

我不确定这是否可行,因为
Seq
可能为空,因此没有要测试的元素。

您可以将提取器与类型检查结合使用:

val first = seq collect { case x @ Bar(_: Foo2)        => x }
val both  = seq collect { case x @ Bar(_: ReadableFoo) => x }
但是返回类型仍然是
List[Bar[Foo]]
。。。因此,如果需要,使用这种方法,您将需要强制转换或重新构造
对象(
大小写条(f:Foo2)=>Bar(f)


对于异类
Seq
我想您是在
Seq
本身上寻找
collect

case class Bar(seq: Seq[Foo])

def onlyFoo2(b: Bar) = Bar(b.seq.collect { case f: Foo2 => f })

onlyFoo2(Bar(Seq(Foo1(), Foo2(1, true))))

我不知道提取器技巧的类型检查,所以我对你的第一个问题的初始解决方案会有点不同。我会为
ReadableFoo

object ReadableFoo { def unapply(x: ReadableFoo) = Some(x.field) }
那你就可以做了

val first = seq collect { case x @ Bar(Foo2(_,_)) => x }
val both  = seq collect { case x @ Bar(ReadableFoo(_)) => x }
但是对于更新的代码,我认为您需要拖拽一个清单

case class Bar[+F <: Foo : Manifest](foo: Seq[F]) { 
    def manifest = implicitly[Manifest[_ <: F]] 
}

case class Bar[+F可能会有帮助。@missingfaktor是的,我想将所有类型参数打印到字符串,然后使用字符串树进行我自己的特殊继承测试是一种方法。这可以链接起来吗,就像
Bar
有一个
foo:Seq[F]
而不仅仅是
foo:F
?如果这能提高清晰度,我可以编辑这个问题。只要你有提取器,是的。它将是
case Bar(Seq(F:Foo2)=>Bar(Seq(F))
——如果你需要返回类型为
Bar[Seq[Foo2]
你需要强制转换或重新生成对象,不是吗
Seq(F:Foo2)
仅匹配一个元素的序列?您是否计划在
Seq
,或所有类型都相同,例如
Seq[Foo2]
?它们将是不同的子类型。它可以是
Foo2
Foo3
Seq
,这样
Bar
Seq
将被
ReadableFoo
参数化。这似乎工作得很好(根据Sciss的建议,在
x
上放置
替代物之后)。有什么问题吗?因为Scala编译器似乎会自动注入那些
def manifest
if
语句,如果这很简单的话?我想这会增加一些开销。编译器只会根据需要注入清单本身,但总是针对数组,因为它们实际上需要映射到Java数组。对于除此之外,它们确实不是经常需要的,也不是经常需要的。在大多数情况下,简单地使用case类/提取器和匹配值就足够了。
case class Bar[+F <: Foo : Manifest](foo: Seq[F]) { 
    def manifest = implicitly[Manifest[_ <: F]] 
}
val first = seq collect {case x if x.manifest <:< manifest[Foo2] => x}
val both = seq collect {case x if x.manifest <:< manifest[ReadableFoo] => x}