斯卡拉的收益是多少?

我了解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 ,返回一系列可能性 - 因为foundfalse 。 只有这样, 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表达式开始与iffor表达。
  • 链接地址: http://www.djcxy.com/p/53787.html

    上一篇: What is Scala's yield?

    下一篇: C# IEnumerator/yield structure potentially bad?