当我使用def在Scala中定义字段时,这意味着什么?

时间:2010-08-16 14:53:18

标签: scala

之间究竟有什么区别:

scala> def foo = 5
foo: Int

scala> def foo() = 5
foo: ()Int

似乎在这两种情况下,我最终得到一个变量foo,我可以引用它而不用括号,总是评估5

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