在Scala中,如何在不是数据成员的类的主构造函数中定义局部参数,例如,仅用于初始化基类中的数据成员?
例如,在以下代码中,如何在类b
的主构造函数中正确定义参数B
,以便它只生成临时本地参数而不是数据成员?
class A(var a: Int)
class B(?b?) extends A(b)
Randall,您的答案解释了为什么Scala编译器在引入方法inc
时会引发属性a
的增加,但也会更改类B
构造函数中参数的名称与类A
构造函数中的参数匹配:
class A(var a: Int)
class B(a: Int) extends A(a) {
def inc(value: Int) { this.a += value }
}
Scala编译器输出:
$ scala construct.scala
construct.scala:3: error: reassignment to val
def inc(value: Int) { this.a += value }
^
one error found
Scala抱怨,因为B
引用了a
中的a
,因此类inc
现在必须拥有私有的只读属性B(a: Int)
。将B(var a: Int)
更改为construct.scala:2: error: error overriding variable a in class A of type Int;
variable a needs `override' modifier
class B(var a: Int) extends A(a) {
^
one error found
会生成不同的编译器错误:
override
添加construct.scala:2: error: error overriding variable a in class A of type Int;
variable a cannot override a mutable variable
class B(override var a: Int) extends A(a) {
^
one error found
也无济于事:
B
如何在A
的主要构造函数中的参数中使用与基类{{1}}的主要构造函数中定义的属性相同的名称?
答案 0 :(得分:16)
如果从构造函数参数中删除“var”或“val”关键字,则它不会生成属性。
请注意,非var,非val构造函数参数是范围内的,并且可以在整个类中访问。如果在非构造函数代码中使用一个代码(即,在方法体中),则生成的类中将存在一个隐藏该构造函数参数的不可见私有字段,就像您将其设置为“private var”或“私有val“构造函数参数。
附录(迟到总比没有好?):
在此代码中,对构造函数参数的引用仅出现在构造函数体中:
class C1(i: Int) {
val iSquared = i * i
val iCubed = iSquared * i
val iEven = i - i % 2
}
...此处值i
仅在执行构造函数期间存在。
但是,在下面的代码中,因为构造函数参数在方法体中引用 - 它不是构造函数体的一部分 - 构造函数参数必须复制到生成的类的(私有)字段中(增加其内存)按住Int
)所需的4个字节的要求:
class C2(i: Int) {
val iSquared = i * i
val iCubed = iSquared * i
val iEven = i - i % 2
def mod(d: Int) = i % d
}
答案 1 :(得分:4)
经过一些实验,我确定在参数var
前面放置val
或b
会使其成为本地参数,而不是数据成员:
class A(var a: Int)
class B(b: Int) extends A(b)
Java扩展:
$ javap -private B
Compiled from "construct.scala"
public class B extends A implements scala.ScalaObject{
public B(int);
}
$ javap -private A
Compiled from "construct.scala"
public class A extends java.lang.Object implements scala.ScalaObject{
private int a;
public A(int);
public void a_$eq(int);
public int a();
public int $tag() throws java.rmi.RemoteException;
}
请注意,由于其主要构造函数中的A
,类a
具有私有数据成员var a: Int
。但是,类B
没有数据成员,但其主构造函数仍然只有一个整数参数。
答案 2 :(得分:4)
您可以在单个类成员的初始化过程中创建临时变量,如下所示:
class A(b:Int){
val m = {
val tmp = b*b
tmp+tmp
}
}
答案 3 :(得分:3)
德里克,
如果你有这个:
class A(a: Int) {
val aa = a // reference to constructor argument in constructor code (no problem)
def m: Float = a.toFloat // reference to constructor argument in method body (causes a to be held in a field)
}
你会发现(使用javap,例如)类中存在名为“a”的字段。如果您注释掉“def m”,那么您将看到该字段未创建。