【问题标题】:flatten Vs flatMap with def method and val function用 def 方法和 val 函数展平 Vs flatMap
【发布时间】:2023-09-23 06:11:01
【问题描述】:

用 def 方法和 val 函数展平 Vs flatMap:

我定义了一个名为 toInt 的 def 方法:

  def toInt(s: String): Option[Int] = {
    try {
      Some(Integer.parseInt(s.trim))
    } catch {
      case e: Exception => None
    }
  }

这种方法适用于 flatten 和 flatMap,如下所示:

//using toInt method
val x = 1.to(5).toList
val y = List("a")
val z = x ++ y
val q = z.map(_.toString)

//using map and flatten
println(q.map(toInt).flatten)
//using flatMap
println(q.flatMap(toInt))

现在我在函数“tooInt”中使用 val 定义了相同的 toInt 功能(如在 def 方法中):

val tooInt: String => Option[Int] = s => {
  try {
    Some(Integer.parseInt(s.trim))
  } catch {
    case c: Exception => None
  }
}

这适用于 flatten 但 NOT 与 flatMap 如下所示:

//using map and flatten
 println(q.map(tooInt).flatten)
 //using flatMap // this has error
 **println(q.flatMap(tooInt))**

您能帮我理解一下吗?

最好的问候, 基兰

【问题讨论】:

    标签: scala flatten flatmap


    【解决方案1】:

    您需要帮助编译器进行一些扩展以使其工作:

    q.flatMap(s => tooInt(s))
    

    这一切都归结为我们在Option.scala 中定义了一个隐含的option2Iterable。当您首先map 然后flatten 时,Option[Int] 已经在范围内并且可以应用隐式。但是当你flatMap 时,编译器必须先将tooInt 扩展为s => tooInt(s),然后再应用隐式解析,但这不起作用。为什么它不起作用?因为编译器会寻找一个隐式类型:

    pt=(=> String => Option[Int]) => (String => scala.collection.GenTraversableOnce[?])
    

    不存在的。反之,先将toInt方法扩展成函数类型,然后隐式搜索Option[Int]

    -- toInt : pt=String => scala.collection.GenTraversableOnce[?] BYVALmode-EXPRmode-POLYmode (site: value r in X)
    |    |    |    |    |    |    |-- { ((s: String) => toInt(s)) } : pt=String => scala.collection.GenTraversableOnce[?] BYVALmode-EXPRmode-POLYmode (site: value r in X)
    |    |    |    |    |    |    |    |-- ((s: String) => toInt(s)) : pt=String => scala.collection.GenTraversableOnce[?] BYVALmode-EXPRmode-POLYmode (site: value r in X)
    |    |    |    |    |    |    |    |    |-- (s: String)Option[Int] : pt=scala.collection.GenTraversableOnce[?] EXPRmode (site: value $anonfun in X)
    |    |    |    |    |    |    |    |    |    |-- s : pt=String BYVALmode-EXPRmode (site: value $anonfun in X)
    |    |    |    |    |    |    |    |    |    |    \-> String
    |    |    |    |    |    |    |    |    |    [search #3] start `(s: String)Option[Int]`, searching for adaptation to pt=Option[Int] => scala.collection.GenTraversableOnce[?] (silent: value $anonfun in X) implicits disabled
    |    |    |    |    |    |    |    |    |    [search #3] considering scala.this.Option.option2Iterable
    

    我们也可以在反编译的代码中看到:

    val r: scala.collection.immutable.IndexedSeq[Int] = q.flatMap[Int, scala.collection.immutable.IndexedSeq[Int]]({
        {
          final <artifact> def $anonfun$main(s: String): Iterable[Int] = scala.this.Option.option2Iterable[Int](toInt(s));
          ((s: String) => $anonfun$main(s))
        }
      }, immutable.this.IndexedSeq.canBuildFrom[Int]());
    

    【讨论】:

    • 甚至 q.flatMap(tooInt(_)) 也可以。我想问题是为什么方法可以传递给 flatMap 而函数文字不能。