首页 文章

Scala:根据模式匹配有条件地在Map定义中添加元素

提问于
浏览
0

我正在尝试在当前项目中尽可能多地使用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, ...
              )

我在此代码段中遇到的问题是无案例 . 如何指定不应在此处添加任何元素?

我尝试了几件事:

  • 我不能在这里引入 {} ,因为它会被解释为 Unit .

  • case None => 之后留下一个空格会导致类型不匹配;因为它也被认为是 Unit 而我们需要 Tuple2 .

  • 我可以在 Map 定义之后执行模式匹配,只在 Some(el) 的情况下添加一个元素 . 但是,这并不是一种非常优雅的方式 .

  • 我可以完全忽略 case None => ,但这会产生警告,因为匹配并非详尽无遗,如果元素确实是 None 则会失败 .

如果我想覆盖Map定义中的所有情况,我怎么能指出在 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 回答

  • 1

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

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

    如果这是您关心的问题,它还会阻止您在 element2 中使用 nullMap .

  • 0

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

  • 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) }
    

相关问题