我有以下代码(简化):
sealed trait Funding {
id: Int
}
final case class FlatRate(id: Int, days: Int, amount: BigDecimal) extends Funding
final case class PerItem(id: Int, amount: BigDecimal, discount: BigDecimal) extends Funding
final case class AppliedFunding[+A <: Funding](
person: String
)
我有一些代码会返回“通用”AppliedFunding
列表,我希望得到一个具有正确类型的特定AppliedFunding
。伪代码:
val allFunding: List[AppliedFunding[Funding]] = <...>
val flatrateFunding: List[AppliedFunding[FlatRate]] = allFunding.someMagicFunction
代替someMagicFunction
我正在寻找一种方法来过滤掉正确的AppliedFunding
个实例并以特定类型返回它们。我可以allFunding.collect { ... }
,但无论我尝试什么,它仍会返回List[AppliedFunding[Funding]]
。
非常感谢任何帮助。
答案 0 :(得分:3)
以下是2种方法。只是侧面标记:collect
是PartialFunction
是好事的极少数情况之一
sealed trait Foo
final case class Bar(i:Int) extends Foo
final case class Baz(d:Double) extends Foo
final case class Container[F <: Foo](s:String, f:F)
val all:List[Container[Foo]] = List(
Container("bar", Bar(3)),
Container("bar", Bar(4)),
Container("bar", Bar(5)),
Container("bar", Bar(6)),
Container("bar", Bar(7)),
Container("baz", Baz(1.5)),
Container("baz", Baz(2.5)),
Container("baz", Baz(3.5)),
Container("baz", Baz(4.5)),
Container("baz", Baz(5.5))
)
val bars:List[Container[Bar]] = all.collect { case Container(s, Bar(i)) => Container(s, Bar(i))}
val baz:List[Container[Baz]] = all.foldRight(List.empty[Container[Baz]]) (
(elem, lst) => elem match {
case Container(s, Baz(d)) => Container(s, Baz(d)) :: lst
case _ => lst
}
)
println(bars)
println(baz)
答案 1 :(得分:0)
以下是有关如何在isInstanceOf
和asInstanceOf
的帮助下完成此操作的解决方案。另一个工作解决方案由Dominic在其他答案中提供,但是对于过滤用例,我不确定为每个通过过滤器的项创建一个新的case类实例是一种正确的方法。此外,使用scalac -print
进行desugaring显示isInstanceOf
调用在这种情况下不会进行任何操作,它将嵌入到生成的isDefinedAt
和applyOrElse
方法中,用于collect
和isInstanceOf
方法中使用的部分函数{1}}。
有些人说使用asInstanceOf
和collect
是一种代码味道,但对我而言,在这种特殊情况下,使用是安全和正确的,并且不会带来{{1调用collect
只是在生成的源代码中隐藏isInstanceOf
并实例化新的案例类实例是对过滤集合上asInstanceOf
的安全调用的权衡。
另请注意,我已在funding
案例类中添加了AppliedFunding
字段。我认为,AppliedFunding
个实例没有关于资金本身的嵌入信息,无论如何都不是很有用。
object Test {
sealed trait Funding {
val id: Int
}
final case class FlatRate(id: Int, days: Int, amount: BigDecimal) extends Funding
final case class PerItem(id: Int, amount: BigDecimal, discount: BigDecimal) extends Funding
final case class AppliedFunding[+A <: Funding](
person: String, funding: A)
val allFundings: List[AppliedFunding[Funding]] = List(AppliedFunding[FlatRate]("alex", FlatRate(1, 10, 100)), AppliedFunding[PerItem]("christian", PerItem(2, 100, 10)))
def flatRatePredicate[A <: Funding](appliedFunding: AppliedFunding[A]): Boolean = appliedFunding.funding.isInstanceOf[FlatRate]
val flatRateFundings: List[AppliedFunding[FlatRate]] = allFundings.filter(flatRatePredicate).asInstanceOf[List[AppliedFunding[FlatRate]]]
def main(args: Array[String]): Unit = {
println(flatRateFundings)
}
}