2009-12-16 8 views
5

Assumer ce code Java:Besoin d'aide avec les variables d'instance de Scala

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

    private int x = 0; 
} 

Si je crée une instance de A, comme celui-ci:

A a = new A("geo"); 

après cet appel, la valeur de x sera 3. Qu'est-ce que je fais de mal dans mon code 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) 
} 

Cette affiche 0. Je suppose que lorsque le compilateur atteint le var x:Int = 0, le corps du constructeur principal a pris fin. Ai-je tort? Sinon, comment pourriez-vous déclarer les variables d'instance dans Scala (en supposant que je ne les veux pas dans mon constructeur)?

+0

Ok, attendons de voir. – Geo

+1

Chaque ligne de code qui n'est pas dans un corps de méthode def est un code constructeur. Val et var code d'initialisation est inclus dans cela et le constructeur est l'accumulation de haut en bas de tout ce code. Notez que ceci inclut des choses comme la méthode * appels * intercalés entre les définitions de val, var et def * *. –

Répondre

7

Gardez à l'esprit que votre code se traduit par quelque chose de similaire (mais pas exactement) à ceci:

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

Mais les variables définies dans les méthodes (non-constructeur) sont traduites en variables locales réelles.

Vous ne savez pas si cela explique le raisonnement autant que met en évidence l'une des différences.


EDIT - Changé « traduction » de scala java pour que la clarté et la capacité de représenter plus précisément ce qui se passe.

+0

Alors, pourquoi pas _ _x' 3? C'est comme ça que je lis la représentation du code. – Geo

+0

Mais comment est traité «x»? En tant que variable locale? Le compilateur le déclare-t-il? – Geo

+0

Modifié pour afficher l'affectation à 0 pour le champ privé. –

4

Modifier ceci:

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

à

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

} 
+0

Pourquoi ne pas en faire un «val»? Il n'y a aucune preuve de l'exemple de code qu'il doit être modifié. –

+0

Ouais, ce serait mieux –

4

var x: Int = 0 faire ce la première ligne du constructeur

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

Votre confusion résulte d'un malentendu sur le fonctionnement des constructeurs de Scala. Plus précisément, Traduisons le code Scala vous en Java posté:

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

devient

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

La raison est simple. Le corps entier d'une classe dans Scala est le constructeur principal pour cette classe. Cela signifie que les instructions qui s'y trouvent, et l'initialisation val et var sont des instructions, seront exécutées dans l'ordre où elles sont trouvées. PS: Voici le véritable rendu réel de ce 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; 
    () 
    } 
    } 
} 
+0

C'est bon de voir que vous avez autant de difficulté que moi à faire des java sans glisser dans les scala-isms. Vous avez manqué un point-virgule et utilisé l'initialiseur de soulignement non-existant-dans-java. –

+0

Je voudrais que Java abandonne déjà le fantôme. :-) –

+0

Ok, le code est fixe, et compilé pour être sûr. Pourquoi Java ne peut-il pas être raisonnable? :-) –

0

Pourquoi Scala vous laissez référence à x avant déclarée? Dans tout autre domaine, ce serait illégal.

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} 
Questions connexes