繁体   English   中英

在 Scala 中使用 def 定义字段是什么意思?

[英]What does it mean when I use def to define a field in Scala?

究竟有什么区别:

scala> def foo = 5
foo: Int

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

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

在任何一种情况下,您都没有定义变量。 您正在定义一个方法。 第一个方法没有参数列表,第二个方法有一个参数列表,它是空的。 其中第一个应该这样调用

val x = foo 

而第二个应该像这样调用

val x = foo()

但是,Scala 编译器将允许您使用一个不带括号的空参数列表调用方法,因此任何一种调用形式都适用于第二种方法。 没有参数列表的方法不能用括号调用

首选的 Scala 风格是定义和调用带有括号的副作用的无参数方法。 没有副作用的无参数方法应该在没有括号的情况下定义和调用。

如果你实际上要定义一个变量,语法是

val foo = 5

在说其他任何事情之前, def没有定义字段,它定义了一个方法。

在第二种情况下,由于 Scala 的特定功能,您可以省略括号。 这里有两个不同的兴趣点:一个是机械的,一个是推荐的用法。

从后者开始,当有副作用时,建议使用空参数列表。 一个经典的例子是close() 如果调用元素没有副作用,则可以省略括号。

现在,作为一个实际的区别——除了在极端情况下可能出现的奇怪的句法混淆(我不是说有,只是推测)——结构类型必须遵循正确的约定。

例如, Source有一个不带括号的close方法,这意味着def close(): Unit的结构类型不会接受Source 同样,如果我将结构方法定义为def close: Unit ,则不会接受 Java closeable对象。

当我在 Scala 中使用 def 定义一个字段时是什么意思

您不能使用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/

除了已经给出的答案,我想强调两点:

  • 在没有参数列表的情况下定义方法的可能性是实现统一访问原则的一种方式。 这允许隐藏字段和方法之间的差异,这使得以后的实现更改更容易。

  • 您可以使用foo调用定义为def foo() = 5方法,但不能使用foo()调用定义为def foo = 5方法

我很惊讶没有人提到懒惰的差异。 虽然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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM