在Scala中,如何在类的主构造函数中定义局部参数?

时间:2009-12-11 17:09:13

标签: scala constructor

在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}}的主要构造函数中定义的属性相同的名称?

4 个答案:

答案 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前面放置valb会使其成为本地参数,而不是数据成员:

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”,那么您将看到该字段未创建。