在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
而不是函数对象?
答案 0 :(得分:2)
与val
或var
声明不同,def i = 3
不是变量声明。您正在定义一个返回常量3
的方法/函数,i
不接受任何参数。
val
和var
的声明会立即得到评估,但是如果是lazy val,则在明确调用时会进行def评估。
i
是一个非参数函数。为了消除混淆,您可以使用空括号来声明它
def i() = 3
lazy val
和def
之间的区别是
延迟评估lazy val并缓存结果。这意味着进一步
每次调用方法名称时都会评估def声明。
使用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;
()
}
}
}
从上面的输出中可以得出以下结论:
definedVal
实际上是一种方法。valVal
是一个在构造函数中初始化并具有自动生成的访问器的字段。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