使用def在scala中定义变量

时间:2016-11-28 13:55:48

标签: scala

在scala中,def用于定义方法,val用于定义变量。

请考虑以下代码:

scala> def i = 3
i: Int

scala> i.getClass()
res0: Class[Int] = int

scala> val v = 2
v: Int = 2

scala> v.getClass()
res1: Class[Int] = int

scala> println(v)
2

scala> println(i)
3

scala> i+v
res4: Int = 5

scala> def o = () => 2+3
o: () => Int

scala> o.getClass()
res5: Class[_ <: () => Int] = class $$Lambda$1139/1753607449

为什么变量定义使用def?如果它定义了一个返回Int的函数,那么为什么getClass显示Int而不是函数对象?

3 个答案:

答案 0 :(得分:2)

valvar声明不同,def i = 3不是变量声明。您正在定义一个返回常量3的方法/函数,i不接受任何参数。

使用valvar

声明会立即得到评估,但是如果是lazy val,则在明确调用时会进行def评估。

i是一个非参数函数。为了消除混淆,您可以使用空括号来声明它

def i() = 3

lazy valdef之间的区别是

  1. 延迟评估lazy val并缓存结果。这意味着进一步

  2. 每次调用方法名称时都会评估def声明。

  3. 使用Scala REPL的示例

    scala> lazy val a = { println("a evaluated"); 1}
    a: Int = <lazy>
    
    scala> def i = { println("i function evaluated"); 2}
    i: Int
    
    scala> a
    a evaluated
    res0: Int = 1
    
    scala> a
    res1: Int = 1
    
    scala> a
    res2: Int = 1
    
    scala> i
    i function evaluated
    res3: Int = 2
    
    scala> i
    i function evaluated
    res4: Int = 2
    
    scala> i
    i function evaluated
    res5: Int = 2
    

    请注意,a仅被评估一次,并且a的进一步调用返回缓存的结果,即lazy val在被调用时被评估一次并且结果被永久存储。所以你看到println输出一次

    每次调用时,都会评估

    通知函数。在这种情况下,每次调用函数

    时都会看到println输出

    一般会议

    当方法有副作用时,有一个使用空参数列表的惯例,当它纯净时将它们关闭。

    编辑

    scala> def i = 1
    i: Int
    
    scala> :type i
    Int
    
    scala> :type i _
    () => Int
    

答案 1 :(得分:2)

编辑:我的回答解决了修订版#3的问题。

在编译过程中查看代码非常有用,您可以在其中查看代码实际转换为的内容。以下简单程序:

object TestApp {
    def definedVal = 3
    val valVal = 3
    lazy val lazyValVal = 3

    def main(args: Array[String]) {
        println(definedVal)
        println(valVal)
        println(lazyValVal)
    }
} 

被翻译为以下(使用-Xprint:mixin编译器选项):

[[syntax trees at end of                     mixin]] // test.scala
package <empty> {
  object TestApp extends Object {
    @volatile private[this] var bitmap$0: Boolean = false;
    private def lazyValVal$lzycompute(): Int = {
      {
        TestApp.this.synchronized({
          if (TestApp.this.bitmap$0.unary_!())
            {
              TestApp.this.lazyValVal = 3;
              TestApp.this.bitmap$0 = true;
              ()
            };
          scala.runtime.BoxedUnit.UNIT
        });
        ()
      };
      TestApp.this.lazyValVal
    };

    def definedVal(): Int = 3;

    private[this] val valVal: Int = _;
    <stable> <accessor> def valVal(): Int = TestApp.this.valVal;

    lazy private[this] var lazyValVal: Int = _;
    <stable> <accessor> lazy def lazyValVal(): Int = if (TestApp.this.bitmap$0.unary_!())
      TestApp.this.lazyValVal$lzycompute()
    else
      TestApp.this.lazyValVal;

    def main(args: Array[String]): Unit = {
      scala.this.Predef.println(scala.Int.box(TestApp.this.definedVal()));
      scala.this.Predef.println(scala.Int.box(TestApp.this.valVal()));
      scala.this.Predef.println(scala.Int.box(TestApp.this.lazyValVal()))
    };
    def <init>(): TestApp.type = {
      TestApp.super.<init>();
      TestApp.this.valVal = 3;
      ()
    }
  }
}

从上面的输出中可以得出以下结论:

  1. definedVal实际上是一种方法。
  2. valVal是一个在构造函数中初始化并具有自动生成的访问器的字段。
  3. 对于惰性字段lazyValVal编译器生成compute方法,该方法在第一次访问该字段时仅调用一次。

答案 2 :(得分:-1)

几乎没有不同的概念。按名称呼叫,按值呼叫并按需拨打电话。所有def本质上都是按名称调用的。你是什​​么意思使用def ??变量定义? 看起来像我的副本: Call by name vs call by value in Scala, clarification needed wiki中的更多细节:https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name