【问题标题】: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 循环和类似情况的原因之一。