斯卡拉的<-
箭似乎有点奇怪。大多数运算符作为函数在源中的某处实现,直接或隐式地在数据类型上定义。另一方面,<-
似乎在for
理解之外似乎无法使用,它作为一个句法元素,用于表示在monadic上下文中绑定新变量(通过map
)。
这是我能想到的唯一一个实例,Scala具有一个只能在特定上下文中使用的符合运算符的语法元素,而且不是一个实际的函数。
我对<-
的工作方式有误吗?它是仅由编译器使用的特殊情况符号,还是开发人员在编写自己的代码时可以使用此行为?
例如,是否可以编写宏来进行转换
forRange (i <- 0 to 10) { print(i) }
进入
{ var i = 0; while (i <= 10) { print(i) } }
而不是标准的map
等价物?据我所知,在i <- ...
上下文之外使用for
会因引用未知值而导致异常。
答案 0 :(得分:6)
简而言之,是<-
是Scala中的保留运算符。这是一个编译器。
<强> FOREACH 强>
foreach
和for 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
语法是flatMap
和map
的糖。此处适用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页),但并不是唯一的。 =>
也是保留字而不是函数。 (还有_
,:
,=
,<:
,<%
,>:
,#
和@
。)所以你无法创建一个具有该名称的函数。我不相信你可以按照你建议的方式调整它(尽管也许更聪明的人会知道一种方式)。你可以创建一个名为`<-`
的函数(带有周围的反向标记),但这可能比它应该更加尴尬。