2009-12-16 11 views
5

Assumere questo codice Java:bisogno di aiuto con le variabili di istanza di Scala

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

    private int x = 0; 
} 

Se creo un 'istanza di A, in questo modo:

A a = new A("geo"); 

dopo questa chiamata, il valore di x sarà 3. Cosa sto sbagliando nel mio codice 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) 
} 

Questo stampa 0. ho pensato che quando il compilatore raggiunge la var x:Int = 0, il corpo del costruttore principale si è concluso. Ho sbagliato? In quale altro modo è possibile dichiarare variabili di istanza in Scala (supponendo che non le vogliano nel mio costruttore)?

+0

Ok, aspettiamo e vediamo. – Geo

+1

Ogni riga di codice che non si trova all'interno di un def (corpo del metodo) è un codice costruttore. Il codice di inizializzazione di Val e var è incluso in questo e il costruttore è l'accumulo top-to-bottom di tutto quel codice. Si noti che questo include cose come il metodo * chiamate * intervallate tra le definizioni val, var e def * *. –

risposta

7

Tenete a mente che il codice si traduce in qualcosa di simile (ma non esattamente) a questo:

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

Ma i vars definiti nei metodi (non di costruzione) vengono convertiti in variabili locali effettive.

Non so se questo spiega il ragionamento tanto quanto evidenzia una delle differenze.


EDIT - Cambiato "traduzione" da Scala a Java per la chiarezza e la capacità di rappresentare in modo più accurato ciò che sta accadendo.

+0

Quindi, perché non era '_x' 3? Ecco come sto leggendo la rappresentazione del codice. – Geo

+0

Ma come viene trattato 'x'? Come variabile locale? Il compilatore lo dichiara? – Geo

+0

Modificato per mostrare l'assegnazione a 0 per il campo privato. –

4

Modifica questo:

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

a

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

} 
+0

Perché non renderlo un 'val'? Non c'è alcuna prova dal codice di esempio che debba essere modificata. –

+0

Sì, sarebbe meglio –

4

var x: int = 0 rendono questa la prima linea del costruttore

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

La tua confusione deriva da un fraintendimento di come funzionano i costruttori in Scala. In particolare, cerchiamo di tradurre il codice Scala che avete inviato in Java:

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

diventa

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

La ragione è semplice. L'intero corpo di una classe in Scala è il costruttore principale di quella classe. Ciò significa che le dichiarazioni in esso contenute e l'inizializzazione di val e var sono istruzioni, verranno eseguite nell'ordine in cui vengono trovate.

PS: Ecco la reale, vera interpretazione di quel codice.

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

È bello vedere che hai tante difficoltà come me a liberare java senza scivolare in scala-ismo. Ti sei perso un punto e virgola e hai usato l'inizializzatore di sottolineatura inesistente in java. –

+0

Vorrei che Java rinunciasse già al fantasma. :-) –

+0

Ok, codice corretto e compilato per essere sicuro. Perché Java non può essere ragionevole? :-) –

0

Perché Scala farvi riferimento x prima dichiarò? In qualsiasi altro ambito, ciò sarebbe illegale.

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} 
Problemi correlati