2009-12-16 13 views
5

asume este código Java:Necesitas ayuda con las variables de instancia de Scala

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

    private int x = 0; 
} 

Si creo una instancia de A, de esta manera:

A a = new A("geo"); 

después de esta llamada, el valor de x será 3. ¿Qué estoy haciendo mal en mi código de 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) 
} 

Esto imprime 0. Supuse que cuando el compilador alcanza el var x:Int = 0, el cuerpo del constructor principal ha terminado. ¿Me equivoco? ¿De qué otra manera podría declarar variables de instancia en Scala (suponiendo que no las quiera en mi constructor)?

+0

Ok, esperemos y veamos. – Geo

+1

Cada línea de código que no está dentro de una definición (cuerpo de método) es código de constructor. El código de inicialización de Val y var está incluido en eso y el constructor es la acumulación de arriba a abajo de todo ese código. Tenga en cuenta que esto incluye cosas como method * calls * intercaladas entre val, var y def * definitions *. –

Respuesta

7

Tenga en cuenta que el código de se traduce en algo similar (pero no exactamente) a esto:

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; 
    } 
} 

Pero los vars definidos en los métodos (no constructor) se traducen en variables locales reales.

No estoy seguro si esto explica el razonamiento tanto como resalta una de las diferencias.


EDITAR - El cambio de "traducción" de Scala de Java para la claridad y la capacidad de representar con mayor precisión lo que está sucediendo.

+0

Entonces, ¿por qué no fue '_x' 3? Así es como estoy leyendo la representación del código. – Geo

+0

Pero, ¿cómo se trata 'x'? Como una variable local? ¿Lo está declarando el compilador? – Geo

+0

Editado para mostrar la asignación a 0 para el campo privado. –

4

cambiar esta situación:

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

a

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

} 
+0

¿Por qué no simplemente convertirlo en un 'val'? No hay evidencia del código de muestra que deba modificarse. –

+0

Sí, eso sería mejor –

4

var x: Int = 0 hacer esto la primera línea del constructor

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

Su confusión se debe a un malentendido sobre cómo funcionan los constructores en Scala. En concreto, vamos a traducir el código Scala informados en Java:

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

convierte

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

La razón es simple. El cuerpo completo de una clase en Scala es el constructor principal para esa clase. Eso significa que las declaraciones en él, y la inicialización de val y var son declaraciones, se ejecutarán en el orden en que se encuentran.

PD: Aquí está la verdadera versión de ese código.

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; 
    () 
    } 
    } 
} 
+0

Es bueno ver que tienes tanta dificultad como yo para entregar java sin deslizarte en scala-ismos. Te perdiste un punto y medio y usaste el inicializador de subrayado inexistente en java. –

+0

Ojalá Java renunciara al fantasma ya. :-) –

+0

Ok, código arreglado y compilado para asegurarse. ¿Por qué Java no puede ser razonable? :-) –

0

¿Por qué dejar que se hace referencia Scala x antes de que lo declaró? En cualquier otro ámbito, esto sería ilegal.

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} 
Cuestiones relacionadas