本文翻译自:What is Scala's yield?

I understand Ruby and Python's yield. 我理解Ruby和Python的收益率。 What does Scala's yield do? Scala的收益率是多少?


#1楼

参考:https://stackoom.com/question/4PnQ/什么是Scala的收益


#2楼

It is used in sequence comprehensions (like Python's list-comprehensions and generators, where you may use yield too). 它用于序列推导 (如Python的列表推导和生成器,您也可以使用yield )。

It is applied in combination with for and 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.toUpperCaseprintln("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. 在Linq。

Ruby's yield has a different effect. Ruby的yield有不同的影响。


#3楼

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's select operator than it is to yield return ). (如果你熟悉C#,那么它更接近LINQ的 select运算符而不是yield return )。


#4楼

Yes, as Earwicker said, it's pretty much the equivalent to LINQ's select and has very little to do with Ruby's and Python's yield . 是的,正如Earwicker所说,它几乎与LINQ的select相当,并且与Ruby和Python的yield几乎没有关系。 Basically, where in C# you would write 基本上,你会写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. 如果你的类型定义只是map ,它允许for由单个发电机的-expressions。
  • If it defines flatMap as well as map , it allows for -expressions consisting of several generators. 如果定义flatMap以及map ,它允许for包括几个发电机-expressions。
  • If it defines foreach , it allows for -loops without yield (both with single and multiple generators). 如果它定义foreach ,它允许for -loops而不产率(都与单个和多个发电机)。
  • If it defines filter , it allows for -filter expressions starting with an if in the for expression. 如果它定义filter ,它允许for -filter表达式开始与iffor表达。

#5楼

I think the accepted answer is great, but it seems many people have failed to grasp some fundamental points. 我认为接受的答案很好,但似乎很多人都未能掌握一些基本要点。

First, Scala's for comprehensions are equivalent to Haskell's do notation, and it is nothing more than a syntactic sugar for composition of multiple monadic operations. 首先,Scala的for内涵等同于Haskell的do记号,它无非是多一元操作组成的语法糖多。 As this statement will most likely not help anyone who needs help, let's try again… :-) 由于这个声明很可能无法帮助任何需要帮助的人,让我们再试一次...... :-)

Scala's for comprehensions is syntactic sugar for composition of multiple operations with map, flatMap and filter . Scala for理解是用于组合多个操作的语法糖,包括map, flatMapfilter Or foreach . 或者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 -expression转换为对这些方法的调用,因此提供它们的任何类或它们的子集都可以用于理解。

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 在Scala 2.7上翻译成

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

    or, on Scala 2.8, into 或者,在Scala 2.8上,进入

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

    with a fallback into the former if method withFilter is not available but filter is. 如果方法withFilter不可用但filter是,则回withFilter前者。 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) => {...}) 

When you look at very simple for comprehensions, the map / foreach alternatives look, indeed, better. 当你看到非常简单for理解时, map / foreach替代品看起来确实更好。 Once you start composing them, though, you can easily get lost in parenthesis and nesting levels. 但是,一旦开始编写它们,就很容易迷失在括号和嵌套级别中。 When that happens, for comprehensions are usually much clearer. 当发生这种情况, 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 <- lel <- slif el > 0
} yield el.toString.length

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. Scala 2.8引入了一个名为withFilter的方法,它的主要区别在于,它不是返回一个新的,已过滤的集合,而是按需过滤。 The filter method has its behavior defined based on the strictness of the collection. filter方法的行为是根据集合的严格性定义的。 To understand this better, let's take a look at some Scala 2.7 with List (strict) and Stream (non-strict): 为了更好地理解这一点,让我们看看一些带有List (严格)和Stream (非严格)的Scala 2.7:

scala> var found = false
found: Boolean = falsescala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9scala> found = false
found: Boolean = falsescala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3

The difference happens because filter is immediately applied with List , returning a list of odds -- since found is false . 之所以出现这种差异是因为filter会立即应用List ,返回一个赔率列表 - 因为found false Only then foreach is executed, but, by this time, changing found is meaningless, as filter has already executed. 只有这样才能执行foreach ,但是,到目前为止,更改found是没有意义的,因为filter已经执行了。

In the case of Stream , the condition is not immediatelly applied. Stream的情况下,不立即应用该条件。 Instead, as each element is requested by foreach , filter tests the condition, which enables foreach to influence it through found . 相反,由于foreach请求每个元素, filter测试条件,这使foreach能够通过found来影响它。 Just to make it clear, here is the equivalent for-comprehension code: 为了说清楚,这里是等效的理解代码:

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 if to be considered on-demand, instead of being applied to the whole collection beforehand. 这导致了许多问题,因为人们期望按需考虑if ,而不是事先应用于整个集合。

Scala 2.8 introduced withFilter , which is always non-strict, no matter the strictness of the collection. Scala 2.8引入了withFilter ,无论收集的严格程度withFilter ,它都是非严格的。 The following example shows List with both methods on Scala 2.8: 以下示例在Scala 2.8上显示了包含这两种方法的List

scala> var found = false
found: Boolean = falsescala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9scala> found = false
found: Boolean = falsescala> 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 filter behaves. 这会产生大多数人期望的结果,而不会改变filter行为方式。 As a side note, Range was changed from non-strict to strict between Scala 2.7 and Scala 2.8. 另外,在Scala 2.7和Scala 2.8之间, Range从非严格变为严格。


#6楼

The keyword yield in Scala is simply syntactic sugar which can be easily replaced by a map , as Daniel Sobral already explained in detail. Scala中的关键字yield只是语法糖 ,可以很容易地用map代替,正如Daniel Sobral已经详细解释过的那样 。

On the other hand, yield is absolutely misleading if you are looking for generators (or continuations) similar to those in Python . 另一方面, 如果您正在寻找类似于Python中的生成器(或延续),则yield绝对会产生误导 See this SO thread for more information: What is the preferred way to implement 'yield' in Scala? 有关更多信息,请参阅此SO线程: 在Scala中实现'yield'的首选方法是什么?

什么是Scala的收益?相关推荐

  1. Scala在挖财的应用实践

    编者按:本文是根据ArchSummit大会上挖财资深架构师王宏江的演讲<Scala在挖财的应用实践>整理而成. \\\\ 这次分享有三个方面,一是介绍一下挖财当前的开发情况和后端的架构, ...

  2. scala编程_Scala可以带回编程的喜悦吗?

    scala编程 编程不再有趣. 这是开发人员Eric Allman在他最新的博客文章中声称的,他继续抱怨说,如今Java开发人员的许多工作包括单调地将库,集成框架,重构,测试和部署现有代码组成. 埃里 ...

  3. 大卫·波拉克(David Pollak)和迪克·沃尔(Dick Wall)讨论了采用Scala的障碍

    著名的Scala倡导者David Pollak写了一篇博客文章, "是的,弗吉尼亚州,Scala很难" ,这在Scala社区引起了一些麻烦. 该帖子声称Scala试图做太多事情,I ...

  4. Tubi x Scala:为什么

    Scala Meetup 上有一个问题被反复提及" Tubi 为什么选择使用 Scala?" Tubi Senior Tech Lead - Alexandros Bantis 在 ...

  5. hadoop,spark,scala,flink 大数据分布式系统汇总

    20220314 https://shimo.im/docs/YcPW8YY3T6dT86dV/read 尚硅谷大数据文档资料 iceberg相当于对hive的读写,starrocks相当于对mysq ...

  6. 2021年大数据常用语言Scala(三十八):scala高级用法 隐式转换和隐式参数

    目录 隐式转换和隐式参数 隐式转换 自动导入隐式转换方法 隐式转换的时机 隐式参数 隐式转换和隐式参数 隐式转换和隐式参数是scala非常有特色的功能,也是Java等其他编程语言没有的功能.我们可以很 ...

  7. 2021年大数据常用语言Scala(三十七):scala高级用法 高阶函数用法

    目录 高阶函数用法 作为值的函数 匿名函数 柯里化(多参数列表) 闭包 高阶函数用法 Scala 混合了面向对象和函数式的特性,在函数式编程语言中,函数是"头等公民",它和Int. ...

  8. 2021年大数据常用语言Scala(三十六):scala高级用法 泛型

    目录 泛型 定义一个泛型方法 定义一个泛型类 上下界 协变.逆变.非变 非变 协变 逆变 泛型 scala和Java一样,类和特质.方法都可以支持泛型.我们在学习集合的时候,一般都会涉及到泛型. sc ...

  9. 2021年大数据常用语言Scala(三十五):scala高级用法 提取器(Extractor)

    目录 提取器(Extractor) 定义提取器 提取器(Extractor)  我们之前已经使用过scala中非常强大的模式匹配功能了,通过模式匹配,我们可以快速匹配样例类中的成员变量.例如: // ...

最新文章

  1. Android自带的emoji表情的使用
  2. Python列表的常用你操
  3. Hibernate的懒加载session丢失解决方法
  4. 反斜杠转义mysql java_mysql数据库中的反斜杠”\“怎么使用Java进行转义
  5. hbase导入csv文件_HBase 数据导入 ImportTsv
  6. python中texttable库显示实时数据_python显示数据库数据
  7. 那一次,我们属于彼此
  8. 读《研发的那些事》有感
  9. c语言不能调用strcat连接两个字符串_C语言中常用的6个字符串处理函数
  10. 华硕服务器 u盘安装系统,华硕电脑u盘安装系统教程
  11. 申城「三日谈」:言汇百家,思通以达(SDCC 2017上海站PPT集锦)
  12. LPR基准利率BP是什么意思,银行利率bp是什么意思
  13. 解决VScode终端管理员运行问题
  14. 有效的运营技巧让中国卖家在跨境电商领域销量翻番
  15. Word中怎么批量修改所有表格样式
  16. Linux中系统的分区管理
  17. Google招聘广告短片的启示
  18. 《PTA——拼题A》之第1016题
  19. 2021年美容师(初级)考试及美容师(初级)考试资料
  20. 计算方法(二):n次多项式插值

热门文章

  1. 清空SQL Server数据库日志的SQL语句
  2. Android开发之通过接口回调机制加载数据(源代码分享)
  3. Android实战技巧之十二:Android Studio导入第三方类库、jar包和so库
  4. 关于虚继承(在钻石继承体系中,一定要用虚继承!)
  5. 算法---删除排序链表中的重复元素 II
  6. 解决编译不通过Could not find support-compat.aar (com.android.support:support-compat:26.0.0).
  7. MethodTrace 生成的trace文件为空
  8. Fragment中使用viewLifecycleOwner/getActivity/this
  9. Android之unable to execute dex java heap space解决方案
  10. Kafka如何对Topic元数据进行细粒度的懒加载、同步等待?