1

在 Eclipse 工作表(2.10.1)中试过这个:

def a = { println("In a"); 3 }                    //> a: => Int
def b() = { println("In b"); 3 }                  //> b: ()Int
val c = () => { println("In c"); 3 }              //> c  : () => Int = <function0>

def test_type(x: => Int) = x                      //> test_type: (x: => Int)Int

test_type(a)                                      //> In a
                                                  //| res0: Int = 3

b()                                               //> In b
                                                  //| res1: Int = 3
c()                                               //> In c
                                                  //| res2: Int = 3

test_type(b)                                      //> In b
                                                  //| res3: Int = 3
// test_type(c) *** Doesn't compile

我肯定错过了一些东西。ab和有什么区别c?在我看来,这a是(统一访问原则?)的“按名称”替代品,val a = 3所以我不能打电话a(),但为什么bc有不同的类型?我也可以b在没有括号的情况下调用(b即将被评估为结果)以及a,并且b在调用时将转换为“按名称” test_type,但c不会和c没有参数将被评估为函数本身(这看起来很合理)。

还有一个问题,Martin Odersky 在他的在线课程中说,如果我做对了,任何匿名函数() => 3都可以替换为{ def f() = 3; f },但是这两个表达式有不同的类型和评估规则,首先将评估为一个函数,其次是函数结果,例如:

val f2 = { def f() = 3; f }                       //> f2  : Int = 3
4

1 回答 1

3

在很多情况下,Scala 以不同的方式处理方法和函数。统一访问原则适用于方法调用,因为方法通常用于模拟对象上的字段,但不适用于函数应用程序。

Whileb是type的方法()Int,代码b将在评估时调用该方法,除非编译器期望使用 where 的函数类型b在这种情况下,它将将该方法 eta 扩展为一个函数。

由于c是type的函数() => Int,因此在所有上下文中都需要明确应用它。所以,test_type(c())应该编译。

的“按名称”-nessx: => Int不会影响这些推理/应用规则;它只影响何时可以评估参数。

scala> object Foo {
     |   def f(): Int = 123
     |   val g: () => Int = () => 123
     | }
defined module Foo

scala> Foo.f
res0: Int = 123

scala> Foo.g
res1: () => Int = <function0>

scala> Foo.g()
res2: Int = 123

scala> (Foo.f: () => Int) // force eta-expansion by explicitly specifying function type
res3: () => Int = <function0>
于 2013-07-14T18:12:28.033 回答