如何在 Scala 中对对象进行模式匹配

Posted

技术标签:

【中文标题】如何在 Scala 中对对象进行模式匹配【英文标题】:How to pattern match objects in Scala 【发布时间】:2021-11-11 15:10:15 【问题描述】:

我正在尝试对对象列表使用模式匹配。该方法采用queue: List[ScheduleChangeEvent]ScheduleChangeEvent 是一个 sealed trait,有 4 个不同的 final case class。因此,根据列表包含的ScheduleChangeEvent 的类型,我需要做一些不同的事情。

我实现了以下内容:

queue match 

      case lsc: List[LocationSettingsChange] =>
        ...
      case lwhc: List[LocationWorkHoursChange] =>
        ...
      case tpc: List[TeamParameterChange] =>
        ...
      case mptc: List[MemberPrimaryTeamChange] =>
        ... 
    

但是,我收到警告 unreachable code [warn] case tpc: List[LocationWorkHoursChange] =>。而且无论传入队列是什么,它总是转到case lac。我明白警告是什么,但我不明白为什么会收到警告。

【问题讨论】:

您正在点击类型擦除,您想要做的事情并不容易完成并且通常不安全。您可以对列表的每个元素进行模式匹配。 是的,我也收到了擦除警告。问题是我真的需要整个队列,是什么让它不安全?谢谢回复。 @LuisMiguelMejíaSuárez 虽然我相信 Shapeless 确实提供了该功能,但您无法真正在运行时检查 List 是否只有一些子类型,这种方式既简单又安全。无论如何,您可以尝试检查列表中的所有元素是否是您的 ADT 的特定实例,但这会很慢并且在某种程度上不安全,或者甚至更好地为您的队列创建一个包装器 ADT。检查这个:scastie.scala-lang.org/BalmungSan/FUVXpbeuR7eqMxgB1887rw/4 【参考方案1】:

这是因为在运行时你有擦除。这意味着 jvm 没有泛型的类型参数值。 IE。而不是 List[LocationSettingsChange]List[LocationWorkHoursChange] 您在运行时只有 List。你可以用非空列表做的事情是一种case head :: tail if head.isInstanceOf[LocationSettingsChange] 的内省,或者如果你有一个提取器的话。 通常尽量避免应该这样做的情况,如果你可以通过将模式匹配从列表传递到列表元素来做类似的事情:

list.map  
  case x: LocationSettingsChange => ???
  case x: LocationWorkHoursChange=> ???
  case x: TeamParameterChange=> ???
  case x: MemberPrimaryTeamChange=> ???

这样做你不会有任何擦除问题,但如果你仍然需要这个,你可以使用类型标签并以运行时性能损失为代价匹配它们,这里描述了更多内容:https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html

【讨论】:

以上是关于如何在 Scala 中对对象进行模式匹配的主要内容,如果未能解决你的问题,请参考以下文章

模式匹配范围在Scala与Spark udf

Scala面向对象和模式匹配

如何在haskell中对两个参数进行模式匹配

如何在 Scala 3 枚举上进行模式匹配

Scala 学习 -- 样例类和模式匹配

Scala 学习 -- 样例类和模式匹配