2012-01-12 9 views
10

Il seguente codice è tratto da Programming in Scala di Martin Odersky et al. che definisce un tipo razionale:È possibile definire una variabile locale del costruttore in Scala?

class Rational(n: Int, d: Int) { 
    require(d != 0) 
    private val g = gcd(n.abs, d.abs) 
    val numer = n/g 
    val denom = d/g 
    ... 
    private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) 
} 

Qui il valore g viene utilizzato solo quando il costruttore implicito inizializza campi numer e denom. Supponiamo che il programmatore sappia che non sarà usato altrove. Nel caso precedente è ancora accessibile dopo la costruzione dell'oggetto Rational. Il che significa che occuperà anche spazio poiché è un campo privato anziché essere una variabile locale per il costruttore.

La mia domanda è come faccio a cambiare il codice affinché g viene utilizzato solo mentre la costruzione e poi gettato via?

+2

Questo è uno di quei "punti icky" in Scala. Immagina che se il dato oggetto costruttore fosse usato solo per estrarre alcune informazioni arbitrarie: averlo in giro per sempre avrebbe impedito di essere idoneo per la bonifica anche se fosse richiesto solo un piccolo sottoinsieme di informazioni. Penso che ci sia una sintassi del "corpo pre-classe", ma non riesco a ricordare quale sia. –

+0

@ pst Grazie per questa rapida modifica stavo facendo così nel frattempo. Il tuo aspetto è migliore. :) – ciuncan

+2

Se qualcuno ha dei collegamenti relativi a questa sintassi del "corpo pre-classe" che citato, sarei interessato a sentirlo. –

risposta

10

In questo caso, come su qualcosa di simile?

class Rational(n: Int, d: Int) { 
    require(d != 0) 
    val (numer, denom) = { 
    val g = gcd(n.abs, d.abs) 
    (n/g, d/g) 
    } 
    private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) 
} 

EDIT: Questo crea anche un campo aggiuntivo che contiene una tupla, come mostrato eseguendo javap sulla classe compilata (grazie, Alexey):

public class Rational extends java.lang.Object implements scala.ScalaObject{ 
    private final scala.Tuple2 x$1; // actually unwanted! 
    private final int numer; 
    private final int denom; 
    public int numer(); 
    public int denom(); 
    private int gcd(int, int); 
    public Rational(int, int); 
} 

In altri casi, a volte uso il blocco locally per evitare di trasformare ogni val in un campo:

class A { 
    locally { 
    val value1 = // ... 
    val value2 = // ... 
    } 
} 
+0

Grazie questa potrebbe essere la soluzione migliore. Ho anche imparato a conoscere il blocco "localmente", quindi grazie ancora. – ciuncan

+0

Posso utilizzare anche valori o variabili definiti nel blocco locale al di fuori di esso, solo nel corpo di questa classe? O sono solo locali per bloccare localmente? – ciuncan

+2

@ciuncan Qualsiasi cosa dichiarata in un blocco di codice (cioè delimitata da parentesi graffe) è accessibile solo all'interno di quel blocco. 'localmente' è solo un metodo comodo per evitare problemi di inferenza del punto e virgola (non una parola chiave), quindi non può cambiarlo. Vedere http://stackoverflow.com/questions/3237727/what-does-predef-locally-do-and-how-is-it-different-from-predef-identity per informazioni su 'locally'. –

Problemi correlati