Scala:根据模式匹配

时间:2017-04-13 13:34:07

标签: scala dictionary pattern-matching

我正在尝试在当前项目中尽可能多地使用Scala功能,但我很难在Map定义中使用模式匹配。

为了说明这一点,请考虑以下代码段:

class Foo(val element: Option[Any], val element2: Any, ...)
val bar = new Foo(...)
val map = Map(bar.element match {
                      case None => ??? // Do not add an item here
                      case Some(el) => "element" -> el
                  }, "element2" -> element2, ...
              )

我在此代码段中遇到的问题是 None 情况。如何指定不应在此处添加任何元素?

我尝试了几件事:

  • 我不能在此处引入{},因为它会被解释为Unit
  • case None =>导致类型不匹配后,只需留空空格;因为它也被视为Unit,而我们需要Tuple2
  • 我可以在 Map定义之后执行模式匹配,仅在Some(el)的情况下添加元素。但是,这并不是一种非常优雅的方式。
  • 我可以完全忽略case None =>,但这会产生警告,因为匹配并非详尽无遗,如果元素确实是None则会失败。

如果我想覆盖地图定义中的所有情况,如何在None的情况下指出不应添加任何元素?

某些上下文:我正在使用它作为特定类型的(akka)喷射json协议定义的一部分,并想知道是否有一种简便的方法来执行此操作而无需有条件地将元素添加到地图。

提前致谢!

编辑:建议的解决方案

基于mavarazy的答案,我已经通过看起来像这样的代码解决了这个问题:

class Foo(val element: Option[Any], val element2: Any, ...)
val bar = new Foo(...)
val map = Map(bar.element match {
                      case None => "" -> null // Do not add an item here
                      case Some(el) => "element" -> el
                  }, "element2" -> element2, ...
              ).filter(_._2 != null)

从未想过这样做,但我认为它仍然有点优雅。谢谢!

3 个答案:

答案 0 :(得分:1)

在选项3上,您可以删除无案例,方法是将.map替换为接收部分函数的.collect

答案 1 :(得分:0)

从我的观点来看,选项3没有任何问题,但如果你不喜欢它,你也可以这样做:

val map = Map(
  "element" -> element,
  "element2" -> Option(element2)
).
  filter(_._2.isDefined).
  mapValues(_.get)

如果这是您关注的问题之一,它还会阻止您Map null element2的{​​{1}}。{/ p>

答案 2 :(得分:0)

使用'collect'将是我的偏好,因为它需要部分函数,​​即只收集与部分函数中指定的模式匹配的那些值 -

val map: Map[String, Option[String]] = Map(
  "element" -> Some("element"),
  "element2" -> Some("element2"),
  "element3" -> None
)
map collect { case (s, Some(e)) => (s, e) }