2011-04-28 133 views
7

我有这种奇怪的情况,我不明白。我正在阅读“Scala编程”一书。 9.奇怪的东西与咖喱功能

比方说,我有一个咖喱功能:

def withThis(n:Int)(op:Int=>Unit){ 
     println("Before") 
     op(n); 
     println("After") 
} 

当我用一个参数调用它一个特殊的花,语法,它按预期工作中:

withThis(5){ 
    (x) => {println("Hello!"); println(x); } 
} 
// Outputs 
Before 
Hello! 
5 
After 

但是,如果我把两个陈述,我得到一些奇怪的:

withThis(5){ 
    println("Hello!") 
    println(_) 
} 
// Outputs 
Hello! 
Before 
5 
After 

怎么来的“你好!”在“之前”之前打印并在内部打印“5”?我疯了吗?

回答

10

你最后的代码示例应改写为产生预期的结果:

withThis(5) { x => 
    println("Hello!") 
    println(x) 
} 

否则,你的例子是相当于

withThis(5) { 
    println("Hello!") 
    (x: Int) => println(x) 
} 

的占位符_会扩展为以非退化方式尽可能紧密地结合(即,它不会扩展到println(x => x))。

要注意的另一件事是块总是返回它的最后一个值。在你的例子中,最后的值实际上是(x: Int) => println(x)

+2

但是println(x => x)甚至不是正确的语法。无论如何 - 我明白println(_)的作用 - 对于这个“块”业务,我更加困惑。 – drozzy 2011-04-28 18:34:20

+0

语法正确。在这种情况下,它不会编译,因为缺少参数类型,但如果编译器可以推断它,则会起作用。简单的例子:'def doit(f:Int => Int)=(); doit(x => x)' – 2011-04-28 18:37:36

+0

我知道它相当于“(x:Int)=> println(x)”,我的问题是为什么它实际上首先执行println。我想你回答“块总是返回最后一个值”。这是否意味着块不会被懒惰评估? – drozzy 2011-05-02 16:55:24

3

在你的第二个例子中,卷曲部分:{ println("Hello!"); println(_) }是一个打印“Hello!”的块。并返回咖啡println。想象一下,它简化为{ println("Hello!"); 5 },它打印“你好!”并返回5

+0

我不认为我在书中“阻挡”了一部分。这就是为什么我很可能会感到困惑。 – drozzy 2011-04-28 18:09:43

+0

因此,在第二个例子中没有办法使它按预期工作?我尝试使用名称参数 - 但他们不接受一个参数。 – drozzy 2011-04-28 18:35:09

+0

只是要挑剔:块不会返回“curried'println'”,而是一个带有一个参数的匿名函数,该函数使用所获取的参数调用println。 – 2011-04-28 18:45:21