【问题标题】:In Scala returning a value from a for loop block在 Scala 中,从 for 循环块返回一个值
【发布时间】:2020-10-05 06:47:13
【问题描述】:

在“不耐烦的 Scala”一书中,它在第 16 页上说

在 Scala 中,{ } 块包含一系列表达式,而 result 也是一个表达式。块的值是 最后一个表达式。

好的,那我们来创建一个block,并让block的最后一个值被赋值:

scala> val evens = for (elem <- 1 to 10 if elem%2==0) {
     |   elem
     | }
val evens: Unit = ()

我原以为evens 至少是序列的最后一个值(即10)。但为什么不呢?

【问题讨论】:

    标签: scala for-loop functional-programming scala-collections


    【解决方案1】:

    你需要yield这个值,那么它就是一个for表达式:

    val evens = for (elem <- 1 to 10 if elem % 2 == 0) yield elem
    

    没有它,它只是一个语句(不返回任何内容)并被翻译为foreach

    P.S.:当然,这将返回满足谓词的所有元素的集合,而不是最后一个。

    【讨论】:

      【解决方案2】:

      如果有疑问,只需通过类型检查器运行它以查看引擎盖下的内容

      scala -Xprint:typer -e 'val evens = for (elem <- 1 to 10 if elem%2==0) { elem }'
      

      揭示

      val evens: Unit = 
        scala.Predef
          .intWrapper(1)
          .to(10)
          .withFilter(((elem: Int) => elem.%(2).==(0)))
          .foreach[Int](((elem: Int) => elem))
      

      我们看到foreach 是链中的最后一步,它的签名是

      def foreach[U](f: A => U): Unit
      

      我们看到它返回Unit。您甚至可以通过执行以下命令直接在 REPL 中执行此操作

      scala> :settings -Xprint:typer
      

      现在您将在 Scala 表达式被解释的同时获得实时脱糖。您甚至可以更进一步,获取 JVM 字节码本身

      scala> :javap -
      

      For-comprehensions 是 Scala 中一些最流行的语法糖,所以我建议尽可能多地练习它们,也许尝试同时在它们的 suggard 和 desugared 中编写它们,直到它点击:@987654321 @

      【讨论】:

      • 很好的解释!
      【解决方案3】:

      Unit 是您书中所述规则的例外。 Unit 基本上说“忽略该块将返回的任何类型,因为我只打算执行该块以产生副作用。”否则,为了让它进行类型检查,你必须在任何应该返回 Unit 的块的末尾添加一个单位值:

      val evens = for (elem <- 1 to 10 if elem%2==0) {
        elem
        ()
      }
      

      这种类型信息的丢弃是人们倾向于避免在 Scala 中使用命令式 for 循环和类似情况的原因之一。

      【讨论】:

        猜你喜欢
        • 2013-01-18
        • 1970-01-01
        • 2013-02-11
        • 1970-01-01
        • 2023-02-14
        • 2014-10-25
        • 1970-01-01
        • 2013-12-30
        • 1970-01-01
        相关资源
        最近更新 更多