在Java中,它们之间的区别很明显。但是在Scala中,可以声明和使用方法而不用括号。我也知道统一访问原则是Scala的理念。这些都使得场和方法之间的界限模糊到一个新的学习者。
一开始,我认为def
和val
是方法和字段之间的边界。但事实证明,在Scala中,使用val
在子类中定义的“field”可以覆盖使用def
在基类中定义的“方法”,这在我知道区分字段概念的任何语言中都是不可能的和方法。
因此我想知道:
Scala中“字段”的概念是否不存在(或完全与无参数方法相同)?
如果没有,他们之间的界限是什么?
答案 0 :(得分:4)
这很简单。例如,对于公共val
scalac生成私有字段来保存值,以及getter。
class A {
val x = 4
}
在javap中你可以看到
public class A {
private final int x;
public int x();
public A();
}
所以,如果你有
trait T { def x = 1 }
当
class A extends T { val x = 4 }
您正在将特征x
中的方法T
覆盖为getter x
到私有字段x
。
答案 1 :(得分:2)
主要差异
def f: Int = something
val v = 1
f
是一种不立即评估的方法。每次显式调用或调用f
时都会评估f
,其中v
会立即进行评估。
通知f
在声明时不会被评估,但在声明时会立即评估x
。在显式调用时会对f
进行评估。
scala> val x = { println("evaluated"); 1}
evaluated
x: Int = 1
scala> def f = { println("evaluated"); 1}
f: Int
scala> f
evaluated
res0: Int = 1
scala> f
evaluated
res1: Int = 1
继承
trait A {
def m: Unit
}
class B extends A {
override val m: Unit = something
}
def
可以覆盖为val
,但反之亦然。我们能够这样做,因为声明val m
会生成一个名为m
的方法。所以它就像在子类型中声明m
来覆盖超类型中的什么。
答案 2 :(得分:2)
在编译器中打开-print
选项时会很清楚:
def m = List(1,2,3)
=>
object iw extends Object {
def m(): List =
scala.collection.immutable.List.apply(
scala.Predef.wrapIntArray(Array[Int]{1, 2, 3})
);
def <init>(): type = {
iw.super.<init>();
()
}
}
VS
val v = List(1,2,3)
=>
object iw extends Object {
private[this] val v: List = _;
<stable> <accessor> def v(): List = iw.this.v;
def <init>(): type = {
iw.super.<init>();
iw.this.v =
scala.collection.immutable.List.apply(
scala.Predef.wrapIntArray(Array[Int]{1, 2, 3})
);
()
}
}
两者都有效地定义了一个方法,但在后一种情况下,私有变量的初始化立即发生,你只需得到它的值,而在每次调用它时都是前者。