之间究竟有什么区别:
scala> def foo = 5
foo: Int
和
scala> def foo() = 5
foo: ()Int
似乎在这两种情况下,我最终得到一个变量foo
,我可以引用它而不用括号,总是评估5
。
答案 0 :(得分:17)
在任何一种情况下,您都没有定义变量。你正在定义一个方法。第一种方法没有参数列表,第二种方法有一个参数列表,它是空的。第一个应该是 这样称呼
val x = foo
而第二个应该像这样调用
val x = foo()
但是,Scala编译器将允许您使用一个没有括号的空参数列表调用方法,因此任何一种调用形式都适用于第二种方法。不能使用括号
调用没有参数列表的方法首选的Scala样式是定义和调用与括号有副作用的无参数方法。没有副作用的无参数方法应该在没有括号的情况下定义和调用。
如果您确实要定义变量,则语法为
val foo = 5
答案 1 :(得分:6)
在说出其他任何内容之前,def
没有定义字段,它定义了一个方法。
在第二种情况下,由于Scala的特定功能,您可以省略括号。这里有两个不同的区别:一个是机械的,一个是推荐用法。
从后者开始,建议在有副作用时使用空参数列表。一个典型的例子是close()
。如果调用元素没有副作用,则省略括号。
现在,作为一个实际的区别 - 除了在极端情况下可能奇怪的句法混淆(我不是说有,只是推测) - 结构类型必须遵循正确的约定。
例如,Source
的{{1}}方法没有括号,这意味着结构类型close
不接受def close(): Unit
。同样,如果我将结构方法定义为Source
,则不会接受Java def close: Unit
对象。
答案 2 :(得分:4)
当我使用def在Scala中定义字段
时,这是什么意思
您无法使用def
定义字段。
似乎在这两种情况下,我最终得到一个变量foo,我可以在没有括号的情况下引用它,总是评估为5。
不,在这两种情况下,您最终都会得到一个方法 foo
,您可以在没有括号的情况下调用它。
要查看,您可以使用javap
:
// Main.scala
object Main {
def foo1 = 5
def foo2() = 5
}
F:\MyProgramming\raw>scalac main.scala
F:\MyProgramming\raw>javap Main
Compiled from "main.scala"
public final class Main extends java.lang.Object{
public static final int foo2();
public static final int foo1();
}
但是,请参阅http://tommy.chheng.com/index.php/2010/03/when-to-call-methods-with-or-without-parentheses-in-scala/
答案 3 :(得分:3)
除了已经给出的答案之外,我还要强调两点:
定义没有参数列表的方法的可能性是实现Uniform Access Principle的一种方法。这允许隐藏字段和方法之间的差异,这使得以后的实现更改更容易。
您可以使用def foo() = 5
调用定义为foo
的方法,但无法使用{{调用定义为def foo = 5
的方法1}}
答案 4 :(得分:0)
我很惊讶没有人提到懒惰的差异。
val
仅在定义时评估一次,而 def
仅在我们访问它时评估并且每次访问时评估。请参见下面的示例:
scala> def foo = {
| println("hi")
| 5
| }
foo: Int
scala> val onlyOnce = foo
scala> def everyTime = foo
scala> onlyOnce
res0: Int = 5
scala> onlyOnce
res1: Int = 5
scala> everyTime
hi
res2: Int = 5
scala> everyTime
hi
res3: Int = 5