Scala "<-" 用于理解
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3754089/
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
Scala "<-" for comprehension
提问by Felix
I have found that Scala always has a "natural explanation" to anything. Always something like "ohh, but that's just a function being called on this and that object with this and that parameter". In a sense, nothing is really compiler-magic as we know it from other languages.
我发现 Scala 总是对任何事情都有“自然的解释”。总是类似于“哦,但这只是在这个和那个对象上调用一个带有这个和那个参数的函数”。从某种意义上说,没有什么是真正的编译器魔法,正如我们从其他语言中所知道的那样。
My question is on the <-operator as used in the following code:
我的问题是关于以下代码中使用的<-运算符:
for(i <- 0 to 10) println(i)
In this example I can see it being rewritten to something like:
在这个例子中,我可以看到它被重写为:
0.to(10).foreach((i:Int)=>println(i))
but this doesn't explain how the igot carried into the anonymous function inside the foreach function. At the point where you write iit is not an object, and not yet a declared variable. So what is it, and how is it being carried over to the inside of foreach?
但这并不能解释i如何进入 foreach 函数内的匿名函数。在您编写i 时,它不是对象,也不是已声明的变量。那么它是什么,它是如何被转移到 foreach 内部的呢?
My guess is that I finally discovered something which is in fact compiler magic
我的猜测是我终于发现了一些实际上是编译器魔术的东西
Thanks for your time.
谢谢你的时间。
To clarify,my question is: how does the <- operator work in the 1st line of code since i is not an object on which it can be called as a function.
澄清一下,我的问题是: <- 运算符如何在第一行代码中工作,因为 i 不是可以作为函数调用的对象。
采纳答案by Randall Schulz
<-is a language-defined keyword symbol, as is =>but in distinct contrast to ->(which is a defined symbol). Because it is part of the basic Scala grammar, it can be used to create bindings (for the iin your example) which is something that cannot be done by user-defined constructs.
<-是语言定义的关键字符号,=>与->(这是一个定义的符号)形成鲜明对比。因为它是基本 Scala 语法的一部分,所以它可用于创建绑定(对于i您的示例中的 ),这是用户定义的构造无法完成的事情。
回答by missingfaktor
To augment Dave's answer, here is a translation schema for 'for-comprehensions' from Scala language specification:
为了补充 Dave 的答案,这里是 Scala 语言规范中“for-comprehensions”的翻译模式:
A comprehension
for (enums) yield eevaluates expressionefor each binding generated by the enumerators enums. An enumerator sequence always starts with a generator; this can be followed by further generators, value definitions, or guards.A generator
p <- eproduces bindings from an expressionewhich is matched in some way against patternp. A value definitionval p = ebinds the value namep(or several names in a patternp) to the result of evaluating the expressione. A guardif econtains a boolean expression which restricts enumerated bindings.The precise meaning of generators and guards is defined by translation to invocations of four methods:
map,filter,flatMap, andforeach. These methods can be implemented in different ways for different carrier types.The translation scheme is as follows. In a first step, every generator
p <- e, where p is not irrefutable (§8.1) for the type ofeis replaced byp <- e.filter { case p => true; case _ => false }Then, the following rules are applied repeatedly until all comprehensions have been eliminated.
A for-comprehension
for (p <- e) yield e0is translated toe.map { case p => e0 }.A for-comprehension
for (p <- e) e0is translated toe.foreach { case p => e0 }.A for-comprehension
for (p <- e; p0 <- e0 . . .) yield e00, where . . . is a (possibly empty) sequence of generators or guards, is translated to:e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }.A for-comprehension
for (p <- e; p0 <- e0 . . .) e00where . . . is a (possibly empty) sequence of generators or guards, is translated to:e.foreach { case p => for (p0 <- e0 . . .) e00 }.A generator
p <- efollowed by a guardif gis translated to a single generator:p <- e.filter((x1, . . . , xn) => g )
wherex1, . . . ,xnare the free variables ofp.A generator
p <- efollowed by a value definitionval p0 = e0is translated to the following generator of pairs of values, wherexandx0are fresh names:val (p, p0) <- for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
推导
for (enums) yield e计算e枚举器枚举生成的每个绑定的表达式。一个枚举器序列总是以一个生成器开始;这之后可以是进一步的生成器、值定义或守卫。生成器
p <- e从e以某种方式与模式匹配的表达式生成绑定p。值定义val p = e将值名称p(或模式中的多个名称p)绑定到表达式的计算结果e。守卫if e包含限制枚举绑定的布尔表达式。发电机和警卫的确切含义是通过翻译定义为四种方法调用:
map,filter,flatMap,和foreach。这些方法可以针对不同的载体类型以不同的方式实现。翻译方案如下。在第一步中,每个生成器
p <- e,其中 p 对于 的类型不是无可辩驳的(第 8.1 节)e被替换为p <- e.filter { case p => true; case _ => false }然后,重复应用以下规则,直到消除所有理解。
一个 for-comprehension
for (p <- e) yield e0被翻译成e.map { case p => e0 }.一个 for-comprehension
for (p <- e) e0被翻译成e.foreach { case p => e0 }.一个 for-comprehension
for (p <- e; p0 <- e0 . . .) yield e00,其中 。. . 是发电机或防护装置的(可能为空)序列被翻译成:e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }。一个理解
for (p <- e; p0 <- e0 . . .) e00where 。. . 是发电机或防护装置的(可能为空)序列被翻译成:e.foreach { case p => for (p0 <- e0 . . .) e00 }。
p <- e后面跟着一个守卫的生成器if g被翻译成一个单独的生成器:p <- e.filter((x1, . . . , xn) => g )
其中x1, 。. . ,xn是 的自由变量p。的发电机
p <- e,随后的值定义val p0 = e0被转换为双值,其中的下列发生器x和x0新鲜的名称:val (p, p0) <- for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
回答by Dave Griffith
In this case, it really is a bit of compiler magic. Translation from for-comprehension to filter/map/flatmap form is a special bit of desugaring, much like conversion of the special forms of update and apply methods.
在这种情况下,它确实有点编译器魔法。从 for-comprehension 到 filter/map/flatmap 形式的转换是一种特殊的脱糖,很像特殊形式的 update 和 apply 方法的转换。

