【问题标题】:Scala - Flatmap a Seq of Options and TraversableScala - 平面映射一系列选项和可遍历
【发布时间】:2016-03-12 22:55:08
【问题描述】:

考虑在某些大小写匹配上编写的 flatMap。例如:

list.flatMap( v =>
    v match {
        case Cond1 => if(something) Some(Int) else None
        //..Other conditions yielding Option[Int]
        case CondN => if(somethingelse) Seq(Int) else Seq()
    })

但是这不会编译。如果 seq 是 Option[Int] 的全部或 Seq[Int] 的全部,则 flatMap 有效。但如果 Seq 是选项和 Seq 的混合体,则不会。为什么会有这样的限制?这是否解决了我目前无法想到的特定歧义。

EDIT1 从 REPL 添加代码 sn-p

scala> val a = Seq(Option(1), Seq(2,3))
a: Seq[Equals] = List(Some(1), List(2, 3))

scala> val b = Seq(Seq(1), Seq(2,3))
b: Seq[Seq[Int]] = List(List(1), List(2, 3))

scala> a.flatMap(x=>x)
<console>:9: error: type mismatch;
 found   : Equals
 required: scala.collection.GenTraversableOnce[?]
              a.flatMap(x=>x)
                           ^

scala> b.flatMap(x=>x)
res24: Seq[Int] = List(1, 2, 3)

EDIT2 在 Filippo 的回答之后,我在 REPL 中尝试了以下代码,它起作用了。

scala> val options = Seq("opt1", "opt2")
options: Seq[String] = List(opt1, opt2)

scala> options.flatMap( x => 
     |      x match {
     |      case "opt1" => Some(1)
     |      case "opt2" => Seq(2,3)
     |      case _ => None
     |      })
res27: Seq[Int] = List(1, 2, 3)

每种情况下的分辨率有何不同。 更重要的是,当我映射而不是 flatMap 时,结果与我创建的 Seq a 相同。

scala> options.map( x => 
 |      x match {
 |      case "opt1" => Some(1)
 |      case "opt2" => Seq(2,3)
 |      case _ => None
 |      })
res28: Seq[Equals] = List(Some(1), List(2, 3))  

【问题讨论】:

  • 你得到什么错误?
  • 你能提供一段我们可以在 REPL 中使用的工作代码吗?
  • @Jus12 更新了问题。

标签: scala flatmap


【解决方案1】:

OptionGenTraversableOnce 但 scala 需要一些帮助:

  val a: Seq[TraversableOnce[Int]] = Seq(Option(1), Seq(2,3))
  a.flatMap(x=>x)

  res0: Seq[Int] = List(1, 2, 3)

编辑添加问题后

我认为,如果您的序列类型是您所期望的,那么一切都归结为传递给 flatMap 的函数。如果scala在起始序列为Seq[A]时无法确定函数为(A) =&gt; Traversable[A],我认为我们应该明确一些类型。

现在,回到您的第一个示例,我将其重构为:

list.flatMap {
  case Cond1 if something     => Seq(Int)
  case CondN if somethingelse => Seq(Int)
  case _                      => Seq()
}

毫无疑问,scala 现在能够正确推断类型。

【讨论】:

  • 我想我问错了问题。我没有用模式匹配检查它。在编写我的应用程序之前,我只是在测试这样的平面图是否可以在 REPL 中工作并且它失败了,但是我将它概括为模式匹配。在您回答之后,我尝试使用它进行模式匹配,并且在这种情况下确实有效。那么在这种情况下如何解决它,而不是当我们显式地创建Seq 时。
  • 实际匹配相当复杂。我创建了一个简单的示例并更新了问题。
  • OptionSeq 是同构的(对于一个元素的序列),对吧?
  • 在某种程度上是的。但也有不同之处。在这个例子中,因为我们所需要的只是将它展平,也许它是一样的。
  • 我想我明白了你所说的 everything boils down to the function passed to the flatMap 的意思。在将函数传递给 flatMap 的情况下,scala 知道结果必须是 TraversableOnce,否则它会尝试将所有可能的返回类型转换为 TraversableOnce 如果将相同的函数编写为独立的函数,因为 Scala 没有进行显式转换产生一个Seq[Equals] 对象。谢谢你的解释。将其标记为正确。
猜你喜欢
  • 2021-12-01
  • 2012-05-14
  • 2022-01-19
  • 2018-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
相关资源
最近更新 更多