Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 类型为泛型类型的筛选器_Scala - Fatal编程技术网

Scala 类型为泛型类型的筛选器

Scala 类型为泛型类型的筛选器,scala,Scala,我有以下代码(简化): 我正在寻找一种方法来代替someMagicFunction筛选出正确的AppliedFunding实例,并将它们与特定类型一起返回。我可以执行allFunding.collect{…},但无论我尝试了什么,它都会返回List[AppliedFunding[Funding]] 非常感谢您的帮助。下面是一个解决方案,说明如何在isInstanceOf和asInstanceOf的帮助下完成此操作。Dominic在另一个答案中提供了另一个工作解决方案,但对于过滤用例,我不确定为通

我有以下代码(简化):

我正在寻找一种方法来代替
someMagicFunction
筛选出正确的
AppliedFunding
实例,并将它们与特定类型一起返回。我可以执行
allFunding.collect{…}
,但无论我尝试了什么,它都会返回
List[AppliedFunding[Funding]]


非常感谢您的帮助。

下面是一个解决方案,说明如何在
isInstanceOf
asInstanceOf
的帮助下完成此操作。Dominic在另一个答案中提供了另一个工作解决方案,但对于过滤用例,我不确定为通过过滤器的每个项目创建一个新的case类实例是正确的方法。此外,使用
scalac-print
进行去糖化表明
isInstanceOf
调用不会去任何地方。在这种情况下,它将嵌入
isDefinedAt
applyOrElse
方法中,用于
collect
中的部分函数

有人说使用
isInstanceOf
asiinstanceof
是一种代码气味,但对我来说,在这种特殊情况下,使用是安全和正确的,并且没有比使用
collect
解决方案带来任何好处:调用
collect
只会在生成的源代码中隐藏
isInstanceOf
编码并实例化新的案例类实例是在筛选的集合上安全调用
asInstanceOf
的一种权衡

另外,请注意,我在
AppliedFunding
案例类中添加了一个
funding
字段。我认为,让
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)
  }
}
对象测试{
封闭式基金{
val id:Int
}
最终案例类统一费率(id:Int,天数:Int,金额:BigDecimal)延长了资金期限
最终案例类PerItem(id:Int,amount:BigDecimal,折扣:BigDecimal)扩展了资金

最后一个案例类AppliedFunding[+A下面是两种方法。只需一句旁注:
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)
Foo
最后一个案例类Bar(i:Int)扩展了Foo
最后一个案例类Baz(d:Double)扩展了Foo
最终案例类容器[F容器(s,Bar(i))}
val baz:List[Container[baz]=all.foldRight(List.empty[Container[baz]])(
(元素,lst)=>元素匹配{
案例容器(s,Baz(d))=>容器(s,Baz(d))::lst
案例=lst
}
)
println(条)
普林顿(巴兹)

在您的情况下,
flatRateFundings
仍将具有类型
列表[AppliedFunding[Funding]]
-它可能包含正确的对象,但类型仍然是超级类型。抱歉。更正。您可以使用模式匹配来解构它,使用
collect
foldX
按类型进行有效过滤。很少情况下需要
isInstanceOf
(除了性能或从外部库获取任何/对象)我认为完全解构每一个case类实例对于过滤用例来说都是过分的。我考虑过这种变体,但无法说服自己,它比简单地使用
isInstanceOf
asiinstanceof
要好。我不知道
asiinstanceof
在内部是如何工作的,也许它也在做类似的事情解构…也许你有更多的知识,所以如果你能分享,我会很高兴。主要是因为它打破了参数化。正如我所说,我可以想象性能考虑是在这种情况下进行转换的一个理由,但只要不是这样,我宁愿解构。你也很有可能用
@
或者类似的东西?呃,你可能可以将大小写匹配公式化得更优雅一点,但我有点懒。抱歉:你可以尝试像
all.collect{case c@Container(u,u:Bar)=>c}
,这有点短,你不必发明更多的变量名。这是否真的那么清楚:我不知道,我实际上发现你的第一个解决方案足够简洁。我总是被
@
匹配弄糊涂,因为我从未使用过它们,但这似乎是这样做的。谢谢!@Andreytukin推断
容器[Foo]
:|哦,你说得对。好吧,那么我收回我的无效建议。你的解决方案是最好的(不仅如此:它实际上是正确的);)
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)
  }
}
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)