斯卡拉的收益是多少?
我了解Ruby和Python的收益。 斯卡拉的收益率是多少?
它用于序列综合(如Python的列表解析和生成器,你也可以使用yield
)。
它与for
组合应用for
并将新元素写入结果序列。
简单的例子(来自斯卡拉朗)
/** Turn command line arguments to uppercase */
object Main {
def main(args: Array[String]) {
val res = for (a <- args) yield a.toUpperCase
println("Arguments: " + res.toString)
}
}
F#中的对应表达式是
[ for a in args -> a.toUpperCase ]
要么
from a in args select a.toUpperCase
在Linq。
Ruby的yield
有不同的影响。
我认为公认的答案很好,但似乎很多人没有把握一些基本点。
首先,Scala的“理解”等同于Haskell的“do”符号,它不过是用于构成多个一元运算的语法糖。 由于这种说法很可能不会帮助任何需要帮助的人,让我们再试一次...... :-)
Scala的“for comprehensions”是语法糖,用于组合使用map,flatMap和filter的多个操作。 或者是foreach。 Scala实际上将for-expression转换为对这些方法的调用,所以提供它们的任何类或它们的子集都可以用于理解。
首先,我们来谈谈翻译。 有非常简单的规则:
1)这
for(x <- c1; y <- c2; z <-c3) {...}
被翻译成
c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
2)这
for(x <- c1; y <- c2; z <- c3) yield {...}
被翻译成
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
3)这个
for(x <- c; if cond) yield {...}
被翻译成Scala 2.7
c.filter(x => cond).map(x => {...})
或者在Scala 2.8上
c.withFilter(x => cond).map(x => {...})
如果使用filter
方法不可用,但是filter
是可用的,则回withFilter
前者。 有关这方面的更多信息,请参阅下面的编辑。
4)这个
for(x <- c; y = ...) yield {...}
被翻译成
c.map(x => (x, ...)).map((x,y) => {...})
当你看到非常简单的理解时,地图/ foreach替代品看起来确实更好。 但是,一旦你开始编写它们,你很容易在括号和嵌套层次上迷失方向。 当发生这种情况时,理解通常要清晰得多。
我会举一个简单的例子,故意省略任何解释。 您可以决定哪种语法更容易理解。
l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))
要么
for{
sl <- l
el <- sl
if el > 0
} yield el.toString.length
编辑
Scala 2.8引入了一个名为withFilter
的方法,主要区别在于,它不是返回一个新的过滤集合,而是按需过滤。 filter
方法根据集合的严格性定义其行为。 为了更好地理解这一点,我们来看看一些Scala 2.7的List
(strict)和Stream
(非严格):
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
发生这种差异的原因是过滤器立即应用List
,返回一系列可能性 - 因为found
是false
。 只有这样, foreach
才会被执行,但是到了这个时候,如果filter
已经执行, found
变化是没有意义的。
在Stream
的情况下,条件不是立即应用的。 相反,由于每个元素都被foreach
请求, filter
测试条件,这使得foreach
可以通过found
影响它。 为了清楚起见,这里是等同的理解代码:
for (x <- List.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
for (x <- Stream.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
这导致了很多问题,因为人们预计if
被视为按需,而不是预先应用于整个集合。
无论收集的严格程度withFilter
,Scala 2.8都会引入withFilter
,它总是非严格的。 以下示例显示Scala 2.8上的两种方法的List
:
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
这产生了大多数人期望的结果,而不会改变filter
行为。 作为一个侧面说明, Range
在Scala 2.7和Scala 2.8之间从非严格改为严格。
是的,正如Earwicker所说的那样,它几乎等同于LINQ的select
,与Ruby和Python的yield
几乎没有关系。 基本上,你会写C#的地方
from ... select ???
在斯卡拉你有
for ... yield ???
理解这一点也很重要, for
-comprehensions不仅适用于序列,而且适用于定义某些方法的任何类型,就像LINQ一样:
map
,它允许for
由单个发电机的-expressions。 flatMap
以及map
,它允许for
包括几个发电机-expressions。 foreach
,它允许for
-loops而不产率(都与单个和多个发电机)。 filter
,它允许for
-filter表达式开始与if
在for
表达。