< - 只能由编译器访问

时间:2013-12-17 16:38:41

标签: scala syntax compiler-construction macros

斯卡拉的<-箭似乎有点奇怪。大多数运算符作为函数在源中的某处实现,直接或隐式地在数据类型上定义。另一方面,<-似乎在for理解之外似乎无法使用,它作为一个句法元素,用于表示在monadic上下文中绑定新变量(通过map )。

这是我能想到的唯一一个实例,Scala具有一个只能在特定上下文中使用的符合运算符的语法元素,而且不是一个实际的函数。

我对<-的工作方式有误吗?它是仅由编译器使用的特殊情况符号,还是开发人员在编写自己的代码时可以使用此行为?

例如,是否可以编写宏来进行转换

forRange (i <- 0 to 10) { print(i) } 

进入

{ var i = 0; while (i <= 10) { print(i) } }

而不是标准的map等价物?据我所知,在i <- ...上下文之外使用for会因引用未知值而导致异常。

2 个答案:

答案 0 :(得分:6)

简而言之,是<-是Scala中的保留运算符。这是一个编译器。

<强> FOREACH

foreachfor yield之间有很大区别,但语法只是语法糖,在编译时转换。

for (i <- 1 to 10) { statement }表达式被翻译为:

Range.from(1, 10).foreach(..)

多个变量: for (i <- 1 to 10; y <- 2 to 100) {..}成为:

Range.from(1, 10).foreach( el => {Range.from(2, 100).foreach(..)});

所有变化由:

for (x <- someList) = someList.foreach(..)

简而言之,它们都会被foreach语句所取消。被调用的特定foreach由使用的集合给出。

收益率

for yield语法是flatMapmap的糖。此处适用stay in the monad规则。

for (x <- someList) yield {..}被翻译为someList.flatMap(..)

链式操作成为map/flatMap组合的分层链:

for { x <- someList; y <- SomeOtherList } yield {}变为:

someList.flatMap(x => { y.flatMap(..) });等等。

要点

关键是<-运算符只不过是语法糖来使代码更具可读性,但它总是在编译时被替换。

强调Rob的观点

Rob提供了其他Scala语法糖的优秀例子。

上下文绑定

package somepackage;
class Test[T : Manifest] {}

实际上翻译为:

class Test[T](implicit evidence: Manifest[T])

作为证明,尝试使用上下文绑定来替换类型:

type TestAlias[T : Manifest] = somepackage.Test // error, the : syntax can't be used.。 或许很容易看出: Manifest部分实际上不是一个类型参数。

输入class Test[T : Manifest]而不是class Test[T](implicit evidence: Manifest[T]更容易。

答案 1 :(得分:2)

<-运算符是该语言中的保留字(请参阅Scala Language Specification,第4页),但并不是唯一的。 =>也是保留字而不是函数。 (还有_:=<:<%>:#@ 。)所以你无法创建一个具有该名称的函数。我不相信你可以按照你建议的方式调整它(尽管也许更聪明的人会知道一种方式)。你可以创建一个名为`<-`的函数(带有周围的反向标记),但这可能比它应该更加尴尬。