需要一些Scala实例变量的帮助

时间:2009-12-16 19:48:41

标签: java oop scala language-features

假设这个Java代码:

public class A {
   public A(String g) {
      x += g.length();
   }

   private int x = 0;
}

如果我创建A的实例,就像这样:

A a = new A("geo");

在此调用之后,x的值将为3.我在Scala代码中出错了什么?

class A(val g:String) {
  x += g.length
  var x:Int = 0
}

object x extends Application {
  val x = new A("geo")
  println(x.x)
}

这打印0.我假设当编译器到达var x:Int = 0时,主构造函数的主体已经结束。我错了吗?你怎么能在Scala中声明实例变量(假设我不想在构造函数中使用它们)?

5 个答案:

答案 0 :(得分:7)

请记住,您的代码会转换为类似的内容(但不完全相反):

public class A {

  private final String g;
  private int x;

  public A(String g) {
    this.g = g;
    x_$eq(x() + g.length());
    x = 0;
  }

  public void x_$eq(int arg0) {
    x = arg0;
  }

  public int x() {
    return x;
  }

  public String g() {
    return g;
  }
}

但是(非构造函数)方法中定义的变量会被转换为实际的局部变量。

不确定这是否能解释其中的原因之一。


编辑 - 为了清晰起见,将scala中的“翻译”更改为java,以及更准确地表示正在发生的事情的能力。

答案 1 :(得分:7)

您对Scala中构造函数的工作原理存在误解,导致您的困惑。具体来说,让我们将您发布的Scala代码翻译成Java:

class A(val g:String) {
  x += g.length
  var x:Int = 0
}

变为

public class A {
   public A(String g) {
      x += g.length();
      x = 0;
   }
   private int x;
}

原因很简单。 Scala中类的整个主体是该类的主要构造函数。这意味着其中的语句以及初始化valvar语句将按照找到的顺序执行。

PS:这是该代码的实际真实再现。

Scala 2.7

C:\Users\Daniel\Documents\Scala\Programas> scalac -print A.scala
[[syntax trees at end of cleanup]]// Scala source: A.scala
package <empty> {
  class A extends java.lang.Object with ScalaObject {
    @remote def $tag(): Int = scala.ScalaObject$class.$tag(A.this);
    <paramaccessor> private[this] val g: java.lang.String = _;
    <stable> <accessor> <paramaccessor> def g(): java.lang.String = A.this.g;
    private[this] var x: Int = _;
    <accessor> def x(): Int = A.this.x;
    <accessor> def x_=(x$1: Int): Unit = A.this.x = x$1;
    def this(g: java.lang.String): A = {
      A.this.g = g;
      A.super.this();
      A.this.x_=(A.this.x().+(g.length()));
      A.this.x = 0;
      ()
    }
  }
}

Scala 2.8

C:\Users\Daniel\Documents\Scala\Programas>scalac -print A.scala
[[syntax trees at end of cleanup]]// Scala source: A.scala
package <empty> {
  class A extends java.lang.Object with ScalaObject {
    <paramaccessor> private[this] val g: java.lang.String = _;
    <stable> <accessor> <paramaccessor> def g(): java.lang.String = A.this.g;
    private[this] var x: Int = _;
    <accessor> def x(): Int = A.this.x;
    <accessor> def x_=(x$1: Int): Unit = A.this.x = x$1;
    def this(g: java.lang.String): A = {
      A.this.g = g;
      A.super.this();
      A.this.x_=(A.this.x().+(g.length()));
      A.this.x = 0;
      ()
    }
  }
}

答案 2 :(得分:4)

改变这个:

class A(val g:String) {
  x += g.length
  var x:Int = 0
}

class A(val g:String) {
  var x = g.length

}

答案 3 :(得分:4)

var x:Int = 0 将此作为构造函数的第一行

class A(val g:String) {  
   var x:Int = 0  
   x += g.length  
}

答案 4 :(得分:0)

为什么Scala允许您在声明之前引用x?在任何其他范围内,这都是非法的。

scala> def foo(g:String) = { x+=1; var x=0; x}
<console>:4: error: forward reference extends over definition of variable x
       def foo(g:String) = { x+=1; var x=0; x}