在我的previous question之后得到了一个快速而且很好的答案,然而事实证明我的例子与我的实际生产代码不匹配。总之,我需要一个新的collect方法实现。
第二个水果世界(有一些非常时髦的果树):
class Fruit {
var seeds:Array[Fruit] = Array()
def naiveCollect[F <: Fruit]:Array[Fruit] = this match {
case f:F => Array(this)
case _ => seeds.map(_.select[F]).flatten.toArray
}
}
class Apple extends Fruit
class Pear extends Fruit
class GrannySmith extends Apple
由于类型擦除而无效:
var tree = new Fruit { seeds = Array(
new Apple,
new Pear,
new GrannySmith,
new Pear { seeds = Array(
new Apple,
new Pear)},
new Apple)}
scala> tree.naiveCollect[Apple]
res1: Array[Fruit] = Array($anon$2@5a4b99fa)
// wanted output: Apple, GrannySmith, Apple, Apple
编辑,解决方案1:
事实证明我设法通过在std lib中使用PartialFunction来生成一些可行的东西。
class Fruit {
...
def clumsyCollect[F](pf:PartialFunction[Fruit, F]):Seq[F] =
if (pf.isDefinedAt(this))
List(pf(this))
else
seeds.flatMap(_.selectPartial[F](pf))
}
用例:
tree.clumsyCollect { case a:Apple => a }
有关清理此事的任何替代方法或提示仍然会很棒!
答案 0 :(得分:1)
我认为您需要的是scala.reflect.ClassManifest
class Fruit {
var seeds:Array[Fruit] = Array()
def select[F <: Fruit](implicit cm: ClassManifest[F]): Array[F] =
if (cm.erasure.isInstance(this))
Array(this.asInstanceOf[F])
else
seeds.flatMap(_.select[F])
}
每次调用select
时,都会传递包含实际类信息的隐式参数。您现在可以在运行时进行类检查,也可以返回更具体类型的Array
。
这会产生所需的结果:
scala> tree.select[Apple]
res12: Array[Apple] = Array(Apple@10fa4d, GrannySmith@a10ca8, Apple@14611ec, Apple@142b533)
或者,您可以使用上下文绑定语法:
def select[F <: Fruit : ClassManifest]: Array[F] =
if (classManifest[F].erasure.isInstance(this))
...
答案 1 :(得分:1)
清单可用于解决擦除问题。由于我们只对清单的擦除感兴趣,我们在这里使用ClassManifest因为它更轻量级。
以下内容很简单,但是select的返回类型是Array [Fruit],而不是Array [F]。
class Fruit {
var seeds: Array[Fruit] = Array()
def select[F <: Fruit](implicit m: ClassManifest[F]): Array[Fruit] =
seeds.filter(s => m.erasure.isInstance(s))
}
以下提供了一个返回类型的数组[F],但更多一些。
class Fruit {
var seeds: Array[Fruit] = Array()
def select[F <: Fruit](implicit m: ClassManifest[F]): Array[F] = {
seeds.foldLeft(Array.newBuilder[F]) { (b, s) =>
if(m.erasure.isInstance(s)) b += s.asInstanceOf[F] else b
}.result
}
}
编辑:我刚注意到我没有回答操作的问题。无论如何,我会留下我的答案,也许这对某人有用。