19

当我第一次开始研究 Scala 时,我喜欢用于理解的外观。它们看起来有点像我在 Java 5 中习惯使用的 foreach 循环,但有功能限制和很多优美的语法。

但是当我吸收了 Scala 风格时,我发现每次我可以使用压缩时,我都在使用map, flatMap, filter, reduceandforeach代替。这样,代码的意图对我来说似乎更清楚,潜在的隐藏惊喜更少,而且它们通常也是更短的代码。

据我所知,无论如何,理解总是被编译成这些方法,所以我想知道:它们实际上是为了什么?我是否错过了一些功能上的更新(这不是第一次)?理解是否能做其他功能不能做的事情,或者至少会更笨拙?它们是否在特定用例下大放异彩?真的只是个人口味的问题吗?

4

5 回答 5

15

请参考这个问题。简短的回答是,理解可以更具可读性。特别是,如果你有很多嵌套的生成器,你正在做的事情的实际范围会变得更加清晰,并且你不需要大的缩进。

于 2009-09-07T01:27:19.867 回答
12

for-comprehension 的另一个重要用途是用于内部 DSL。 ScalaQL就是一个很好的例子。可以转这个

val underAge = for { 
  p <- Person 
  c <- Company 
  if p.company is c 
  if p.age < 14 
} yield p 

进入这个

SELECT p.* FROM people p JOIN companies c ON p.company_id = c.id WHERE p.age < 14 

还有更多。

于 2009-09-07T03:15:04.733 回答
10

for-comprehensions 是语法糖,但这并不意味着它们不重要。它们通常比扩展形式更简洁,这很好,但也许更重要的是,它们帮助命令式语言的程序员使用函数式构造。

当我第一次开始使用 Scala 时,我经常使用 for-comprehensions,因为它们很熟悉。然后我几乎完全停止了,因为我觉得使用底层方法更明确,因此更清晰。现在我又开始使用 for-comprehensions,因为我认为它们更好地表达了我正在做的事情的意图,而不是做这件事的方式。

于 2009-09-06T16:29:34.357 回答
5

在某些情况下,因为理解可以更好地表达意图,所以当他们这样做时,使用它们。

另请注意,使用 for 推导式,您可以免费获得模式匹配。例如,使用 for comprehension 对 Map 进行迭代要简单得多:

for ((key, value) <- map) println (key + "-->" + value)

与 foreach 相比:

map foreach { case (key, value) => println (key + "-->" + value) }

于 2011-09-05T14:27:45.810 回答
3

你说的对。for-comprehension 是语法糖。我相信,一旦你习惯了底层的方法,它们就会更简洁、更容易阅读。

比较以下等效语句:

1. for (i <- 1 to 100; if (i % 3 == 0)) yield Math.pow(i, 2)
2. (1 to 100).filter(_ % 3 == 0).map(Math.pow(_, 2))

在我看来,在#1 中添加分号会分散人们认为这是一个单链语句的感觉。还有一种感觉是 i 是一个 var(是 1,还是 99,或者介于两者之间?),这有损于其他功能样式。

选项 2 显然是对对象的一系列方法调用。链条中的每个环节都清楚地说明了它的责任。没有中间变量。

也许为了方便从 Java 转换的开发人员,包含了推导式。无论如何,选择哪一个是风格和偏好的问题。

于 2009-09-06T23:09:44.037 回答