在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
我肯定错过了一些东西。 a
,b
和c
之间的区别是什么?在我看来,a
是val a = 3
(统一访问原则?)的“名字”替代品,因此我无法调用a()
,但为什么b
和{ {1}}有不同的类型?我也可以在没有括号的情况下调用c
(即b
将被评估为结果)以及b
,a
将被转换为“按名称”调用b
,但test_type
将不会和c
没有参数将被评估为函数本身(看起来合理)。
还有一个问题,Martin Odersky在他的在线课程中说,如果我做对了,c
这样的任何匿名函数都可以用() => 3
代替,但这两个表达式有不同的类型和评价规则,首先将被评估为函数,第二个是函数结果,例如:
{ def f() = 3; f }
答案 0 :(得分:3)
在许多情况下,Scala以不同方式处理方法和函数。统一访问原则适用于方法调用,因为方法通常用于模仿对象上的字段,但不能用于函数应用程序。
虽然b
是()Int
类型的方法,但代码b
将在评估时调用该方法,除非编译器需要一个函数输入使用b
的类型,在这种情况下,它会将方法扩展为函数。
由于c
是() => Int
类型的函数,因此应用它需要在所有上下文中都是显式的。所以,test_type(c())
应该编译。
x: => 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>