Scala 的收益率是多少?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1052476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:29:10  来源:igfitidea点击:

What is Scala's yield?

scalafunctional-programmingyield

提问by Geo

I understand Ruby and Python's yield. What does Scala's yield do?

我了解 Ruby 和 Python 的收益。Scala 的 yield 有什么作用?

采纳答案by Dario

It is used in sequence comprehensions(like Python's list-comprehensions and generators, where you may use yieldtoo).

它用于序列推导式(如 Python 的列表推导式和生成器,您也可以使用yield)。

It is applied in combination with forand writes a new element into the resulting sequence.

它与for结果序列结合使用并将新元素写入结果序列中。

Simple example (from scala-lang)

简单示例(来自scala-lang

/** 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)
  }
}

The corresponding expression in F# would be

F# 中的相应表达式为

[ for a in args -> a.toUpperCase ]

or

或者

from a in args select a.toUpperCase 

in Linq.

在林克。

Ruby's yieldhas a different effect.

Rubyyield有不同的效果。

回答by Daniel C. Sobral

I think the accepted answer is great, but it seems many people have failed to grasp some fundamental points.

我认为接受的答案很好,但似乎很多人未能掌握一些基本要点。

First, Scala's forcomprehensions are equivalent to Haskell's donotation, and it is nothing more than a syntactic sugar for composition of multiple monadic operations. As this statement will most likely not help anyone who needs help, let's try again… :-)

首先,Scala 的for推导相当于 Haskell 的do记法,它只不过是多个 monadic 操作组合的语法糖。由于此声明很可能无法帮助任何需要帮助的人,让我们再试一次……:-)

Scala's forcomprehensions is syntactic sugar for composition of multiple operations with map, flatMapand filter. Or foreach. Scala actually translates a for-expression into calls to those methods, so any class providing them, or a subset of them, can be used with for comprehensions.

Scala 的for推导式是用 mapflatMap和组合多个操作的语法糖filter。或者foreach。Scala 实际上将 -for表达式转换为对这些方法的调用,因此任何提供它们的类或它们的子集都可以用于推导。

First, let's talk about the translations. There are very simple rules:

首先,让我们谈谈翻译。有非常简单的规则:

  1. This

    for(x <- c1; y <- c2; z <-c3) {...}
    

    is translated into

    c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
    
  2. This

    for(x <- c1; y <- c2; z <- c3) yield {...}
    

    is translated into

    c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
    
  3. This

    for(x <- c; if cond) yield {...}
    

    is translated on Scala 2.7 into

    c.filter(x => cond).map(x => {...})
    

    or, on Scala 2.8, into

    c.withFilter(x => cond).map(x => {...})
    

    with a fallback into the former if method withFilteris not available but filteris. Please see the section below for more information on this.

  4. This

    for(x <- c; y = ...) yield {...}
    

    is translated into

    c.map(x => (x, ...)).map((x,y) => {...})
    
  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 => {...})
    

    如果方法withFilter不可用但可用,filter则回退到前者。有关这方面的更多信息,请参阅以下部分。

  4. for(x <- c; y = ...) yield {...}
    

    被翻译成

    c.map(x => (x, ...)).map((x,y) => {...})
    

When you look at very simple forcomprehensions, the map/foreachalternatives look, indeed, better. Once you start composing them, though, you can easily get lost in parenthesis and nesting levels. When that happens, forcomprehensions are usually much clearer.

当您查看非常简单的for推导式时,map/foreach选项看起来确实更好。但是,一旦开始编写它们,您就很容易迷失在括号和嵌套级别中。当这种情况发生时,for理解通常会清晰得多。

I'll show one simple example, and intentionally omit any explanation. You can decide which syntax was easier to understand.

我将展示一个简单的例子,并有意省略任何解释。您可以决定哪种语法更容易理解。

l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))

or

或者

for {
  sl <- l
  el <- sl
  if el > 0
} yield el.toString.length


withFilter

withFilter

Scala 2.8 introduced a method called withFilter, whose main difference is that, instead of returning a new, filtered, collection, it filters on-demand. The filtermethod has its behavior defined based on the strictness of the collection. To understand this better, let's take a look at some Scala 2.7 with List(strict) and Stream(non-strict):

Scala 2.8 引入了一个名为 的方法withFilter,其主要区别在于,它不是返回一个新的、过滤的集合,而是按需过滤。该filter方法的行为基于集合的严格性定义。为了更好地理解这一点,让我们来看看一些带有List(严格)和Stream(非严格)的Scala 2.7 :

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

The difference happens because filteris immediately applied with List, returning a list of odds -- since foundis false. Only then foreachis executed, but, by this time, changing foundis meaningless, as filterhas already executed.

之所以产生差异,filter是因为立即应用了List,返回了一个赔率列表——因为foundfalse。只有那时foreach才被执行,但是,此时,更改found已无意义,因为filter已经执行了。

In the case of Stream, the condition is not immediatelly applied. Instead, as each element is requested by foreach, filtertests the condition, which enables foreachto influence it through found. Just to make it clear, here is the equivalent for-comprehension code:

在 的情况下Stream,条件不会立即应用。相反,当 请求每个元素时foreach,会filter测试条件,从而能够foreach通过 影响它found。为了清楚起见,这里是等效的 for-comprehension 代码:

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)

This caused many problems, because people expected the ifto be considered on-demand, instead of being applied to the whole collection beforehand.

这导致了许多问题,因为人们期望将if其视为按需,而不是事先应用于整个集合。

Scala 2.8 introduced withFilter, which is alwaysnon-strict, no matter the strictness of the collection. The following example shows Listwith both methods on Scala 2.8:

Scala 2.8 引入了withFilter,无论集合的严格程度如何,它始终是非严格的。以下示例显示List了 Scala 2.8 上的两种方法:

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

This produces the result most people expect, without changing how filterbehaves. As a side note, Rangewas changed from non-strict to strict between Scala 2.7 and Scala 2.8.

这会产生大多数人期望的结果,而不会改变filter行为方式。作为旁注,Range在 Scala 2.7 和 Scala 2.8 之间从非严格改为严格。

回答by Alexey Romanov

Yes, as Earwicker said, it's pretty much the equivalent to LINQ's selectand has very little to do with Ruby's and Python's yield. Basically, where in C# you would write

是的,正如 Earwicker 所说,它几乎等同于 LINQselect并且与 Ruby 和 Python 的yield. 基本上,您将在 C# 中编写

from ... select ??? 

in Scala you have instead

在 Scala 中,你有

for ... yield ???

It's also important to understand that for-comprehensions don't just work with sequences, but with any type which defines certain methods, just like LINQ:

同样重要的是理解for-comprehensions 不仅适用于序列,还适用于定义某些方法的任何类型,就像 LINQ:

  • If your type defines just map, it allows for-expressions consisting of a single generator.
  • If it defines flatMapas well as map, it allows for-expressions consisting of several generators.
  • If it defines foreach, it allows for-loops without yield (both with single and multiple generators).
  • If it defines filter, it allows for-filter expressions starting with an ifin the forexpression.
  • 如果您的类型只定义了map,则它允许for由单个生成器组成的 - 表达式。
  • 如果它定义flatMap以及map,则它允许for由多个生成器组成的 - 表达式。
  • 如果它定义了foreach,则它允许for没有 yield 的 -loops(带有单个和多个生成器)。
  • 如果它定义了filter,则它允许for-filter 表达式iffor表达式中以 an 开头。

回答by Daniel Earwicker

Unless you get a better answer from a Scala user (which I'm not), here's my understanding.

除非您从 Scala 用户(我不是)那里得到更好的答案,否则这是我的理解。

It only appears as part of an expression beginning with for, which states how to generate a new list from an existing list.

它仅作为以 开头的表达式的一部分出现,该表达式for说明如何从现有列表生成新列表。

Something like:

就像是:

var doubled = for (n <- original) yield n * 2

So there's one output item for each input (although I believe there's a way of dropping duplicates).

所以每个输入都有一个输出项(尽管我相信有一种方法可以删除重复项)。

This is quite different from the "imperative continuations" enabled by yield in other languages, where it provides a way to generate a list of any length, from some imperative code with almost any structure.

这与其他语言中由 yield 启用的“命令式延续”完全不同,它提供了一种从几乎任何结构的命令式代码生成任意长度列表的方法。

(If you're familiar with C#, it's closer to LINQ'sselectoperator than it is to yield return).

(如果您熟悉 C#,则它更接近LINQ 的select运算符而不是yield return)。

回答by Richard Gomes

The keyword yieldin Scala is simply syntactic sugarwhich can be easily replaced by a map, as Daniel Sobral already explainedin detail.

yieldScala 中的关键字只是语法糖,可以很容易地替换为 a map,正如Daniel Sobral 已经详细解释的那样

On the other hand, yieldis absolutely misleading ifyou are looking for generators (or continuations) similar to those in Python. See this SO thread for more information: What is the preferred way to implement 'yield' in Scala?

另一方面,yield如果您正在寻找类似于Python 中的生成器(或延续),则绝对具有误导性。有关更多信息,请参阅此 SO 线程:在 Scala 中实现“产量”的首选方法是什么?

回答by Mario Galic

Consider the following for-comprehension

考虑以下理解

val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i

It may be helpful to read it out loud as follows

大声朗读如下可能会有所帮助

"Foreach integer i, ifit is greater than 3, then yield(produce) iand add it to the list A."

对于每个整数i如果它大于3,则产生(产生)i并将其添加到列表中A。”

In terms of mathematical set-builder notation, the above for-comprehension is analogous to

就数学集合构建器表示法而言,上述 for-comprehension 类似于

set-notation

集合符号

which may be read as

可以读作

"Foreach integer i, ifit is greater than 3, then it is a memberof the set A."

对于每个整数一世如果它大于3,那么它就是集合的成员一个。”

or alternatively as

或者作为

"Ais the set of all integers i, such that each iis greater than 3."

"一个是所有整数的集合一世,使得每个一世都大于3。"

回答by Manasa Chada

Yield is similar to for loop which has a buffer that we cannot see and for each increment, it keeps adding next item to the buffer. When the for loop finishes running, it would return the collection of all the yielded values. Yield can be used as simple arithmetic operators or even in combination with arrays. Here are two simple examples for your better understanding

Yield 类似于 for 循环,它有一个我们看不到的缓冲区,并且对于每个增量,它不断向缓冲区添加下一项。当 for 循环完成运行时,它将返回所有产生值的集合。Yield 可以用作简单的算术运算符,甚至可以与数组结合使用。这里有两个简单的例子让你更好地理解

scala>for (i <- 1 to 5) yield i * 3

res: scala.collection.immutable.IndexedSeq[Int] = Vector(3, 6, 9, 12, 15)

res: scala.collection.immutable.IndexedSeq[Int] = Vector(3, 6, 9, 12, 15)

scala> val nums = Seq(1,2,3)
nums: Seq[Int] = List(1, 2, 3)

scala> val letters = Seq('a', 'b', 'c')
letters: Seq[Char] = List(a, b, c)

scala> val res = for {
     |     n <- nums
     |     c <- letters
     | } yield (n, c)

res: Seq[(Int, Char)] = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))

res: Seq[(Int, Char)] = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), ( 3,a), (3,b), (3,c))

Hope this helps!!

希望这可以帮助!!

回答by dotnetN00b

val aList = List( 1,2,3,4,5 )

val res3 = for ( al <- aList if al > 3 ) yield al + 1
val res4 = aList.filter(_ > 3).map(_ + 1)

println( res3 )
println( res4 )

These two pieces of code are equivalent.

这两段代码是等价的。

val res3 = for (al <- aList) yield al + 1 > 3
val res4 = aList.map( _+ 1 > 3 )

println( res3 ) 
println( res4 )

These two pieces of code are also equivalent.

这两段代码也是等价的。

Map is as flexible as yield and vice-versa.

Map 和 yield 一样灵活,反之亦然。

回答by Michael Peng

yield is more flexible than map(), see example below

yield 比 map() 更灵活,见下面的例子

val aList = List( 1,2,3,4,5 )

val res3 = for ( al <- aList if al > 3 ) yield al + 1 
val res4 = aList.map( _+ 1 > 3 ) 

println( res3 )
println( res4 )

yield will print result like: List(5, 6), which is good

yield 会打印如下结果:List(5, 6),这很好

while map() will return result like: List(false, false, true, true, true), which probably is not what you intend.

而 map() 将返回如下结果:List(false, false, true, true, true),这可能不是您想要的。