无参方法与小括号问题

微博上看到有人问:def fun=1def fun()=1有什么区别

对于为什么会有无参风格的def,参考这篇笔记: scala中的无参方法与统一访问原则 ,这里另外对无参函数与apply方法再做个补充

scala里允许带有小括号(无参)的方法在调用时省略小括号:

scala> def foo() = println("hi")

scala> foo  //等同于foo()
hi

但对于没有小括号(without parenthesis)的方法,调用时若增加了小括号却是意义不同的:

scala> def bar = println("hi")

scala> bar
hi

scala> bar()
<console>:9: error: Unit does not take parameters

上面的例子直接报错。这是因为 bar() 实际被翻译为 (bar).apply() 但因为bar方法的返回值是Unit,它没有apply方法,所以报错(编译期错误)。

自定义一个带apply方法的类看看:

scala> class MyClass { def apply() = println("haha") }

scala> def m = new MyClass  

scala> m
res0: MyClass = MyClass@6ef93d8a

scala> m() //对m方法得到的结果再执行apply方法
haha

也有些类中的apply方法是接受参数的,比如一些集合用apply(i:Index)来遍历里面的元素:

scala> def foo = "hello"
foo: String

scala> foo(0) //翻译为(foo).apply(0)
res3: Char = h

apply方法是一种语法糖,可以用小括号来表示,不要与方法本身的小括号混淆。这个例子对初学者也算是一个陷阱吧。

//补充
另外,看看def foodef foo()这两种风格的表达是怎么在class里描述的,因为转化为java后发现是一致的:
http://stackoverflow.com/questions/10130106/how-does-scala-know-the-difference-between-def-foo-and-def-foo

通过 javap 看到的结果是一样的,但实际上scala会将信息存入子啊 class文件中的ScalaSig属性中。
通过 javap -verbose能够看到ScalaSig属性的二进制数据。

发表评论

电子邮件地址不会被公开。 必填项已用*标注