微博上看到有人问:def fun=1
和def 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 foo
与 def 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属性的二进制数据。
def xyz={…}
可以把def xyz看成val xyz,就是把xyz当做变量使用