占位符语法不能保留我的位置

时间:2013-07-15 06:36:43

标签: scala

我已经阅读了其他一些问题,例如What are all the uses of an underscore in Scala?,虽然我确定已经提出过这个问题,但我无法解决所有其他17000个Scala问题。

Foreach have strange behaviourPlaceholder not useful,但它似乎仍然是hidden feature

scala> val is = (1 to 5) toList
is: List[Int] = List(1, 2, 3, 4, 5)

scala> is foreach { i => println("Hi.") ; Console println 2 * i }
Hi.
2
Hi.
4
Hi.
6
Hi.
8
Hi.
10

scala> is foreach { println("Hi.") ; Console println 2 * _ }
Hi.
2
4
6
8
10

有人可以解释一下我的区别吗?

如果你感到一阵热情并尝试:

scala> is foreach { i => println("Hi!") ; Console println 2 * i }
java.lang.IllegalArgumentException: !") ; Console println 2 * i }: event not found

然后看this answer.并且确实发生了。

2 个答案:

答案 0 :(得分:7)

占位符语法适用于一个表达式,而不适用于整个块,因此您的示例被解释为{ println("Hi."); i => Console println 2 * i }

答案 1 :(得分:3)

Landei有正确的答案,我认为,但它并没有彻底解开。让我们从最后开始:

scala> Console println 2 * _
<console>:8: error: missing parameter type for expanded function
((x$1) => Console.println(2.$times(x$1)))
              Console println 2 * _
                                  ^

好的,所以我们看到它自己Console println 2 * _试图通过显式eta扩展来创建一个函数,除了它不知道返回参数类型所以它不能。

现在让我们尝试一个返回函数的代码块。

scala> { println("Hi"); (i: Int) => i*5 }
Hi
res1: Int => Int = <function1>

因此,与所有内容一样,您执行整个块(包括像println这样的副作用语句),并返回作为函数的返回值。

现在,正如Landei所说,占位符语法仅适用于一个(简单)表达式中的一个参数,而在第二种情况下,我们没有简单表达式而是块表达式(由两个简单表达式组成)。所以我们使用占位符语法,我们正在创建一个函数。我们在代码块中执行此操作:

is foreach { println("Hi.") ; Console println 2 * _ }

由于我们不以函数参数开头,因此被解释为普通参数,除了我们几乎可以在任何上下文中包含参数列表 - 用块表达式{替换简单表达式(x) {1}}。所以我们可以把它想象成

{ stuff; x }

现在类型推断器知道返回类型应该是什么,因此它运行该代码块,打印出“Hi”并创建一个函数,然后将该函数(仅在开始时一次!)传递给{{ 1}}。如果类型推断器可以查看线条以找出类型,那么它将等同于:

is foreach ({ println("Hi.") ; Console.println 2 * _ })