Примите этот код 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 (предполагающий, что я не хочу их в своем конструкторе)?
Имейте в виду, что ваш код переводится во что-то похожее (но не совсем) на это:
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 для ясности и возможности более точно представлять, что происходит.
Your confusion results from a misunderstanding of how constructors in Scala works. Specifically, let's translate the Scala code you posted into Java:
class A(val g:String) {
x += g.length
var x:Int = 0
}
becomes
public class A {
public A(String g) {
x += g.length();
x = 0;
}
private int x;
}
The reason is simple. The whole body of a class in Scala is the primary constructor for that class. That means the statements in it, and initializing val
and var
are statements, will be executed in the order they are found.
PS: Here is the actual, true rendition of that code.
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;
()
}
}
}
Измените это:
class A(val g:String) {
x += g.length
var x:Int = 0
}
на
class A(val g:String) {
var x = g.length
}
var x: Int = 0 сделайте это первой строкой конструктора
class A(val g:String) {
var x:Int = 0
x += g.length
}
Почему 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}