2012-01-12 24 views
10

El siguiente código está tomado de la Programación en Scala book de Martin Odersky et al. que define un tipo racional:¿Es posible definir una variable de constructor local en 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) 
} 

Aquí el valor g sólo se utiliza cuando el constructor implícito inicializa campos numer y denom. Supongamos que el programador sabe que no se usará en ningún otro lado. En el caso anterior, sigue siendo accesible después de la construcción del objeto Rational. Lo que significa que también ocupará espacio ya que es un campo privado en lugar de ser una variable local para el constructor.

Mi pregunta es ¿cómo puedo cambiar este código para que g solo se use durante la construcción y luego se deseche?

+2

Este es uno de esos "puntos icky" en Scala. Imagínese que si el objeto constructor dado solo se usara para extraer alguna información arbitraria: tenerlo por siempre evitaría que sea elegible para la recuperación, incluso si solo se necesita un pequeño subconjunto de información. Creo que hay una sintaxis de "cuerpo pre-clase", pero no recuerdo qué es. –

+0

@pst Gracias por esta rápida edición lo estaba haciendo mientras tanto. La tuya se ve mejor sin embargo. :) – ciuncan

+2

Si alguien tiene algún vínculo con respecto a esta sintaxis de "cuerpo pre-clase" que pst menciona, me interesaría saber al respecto. –

Respuesta

10

En este caso, ¿qué tal algo como esto?

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: Esto también crea un campo adicional que contiene una tupla, como se muestra mediante la ejecución de javap en la clase compilada (gracias, 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); 
} 

En otros casos, a veces uso el bloque locally para evitar girar cada val en un campo:

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

Gracias esta podría ser la mejor solución. También aprendí sobre bloque "local", así que gracias de nuevo. – ciuncan

+0

¿Puedo usar valores o variables definidos en bloque local fuera de él, solo en ese cuerpo de clase? ¿O son locales para bloquear localmente? – ciuncan

+2

@ciuncan Cualquier cosa declarada en un bloque de código (es decir, delimitada por llaves) solo es accesible dentro de ese bloque. 'localmente 'es solo un método conveniente para evitar problemas de inferencia de punto y coma (no una palabra clave), por lo que no puede cambiar esto. Consulte http://stackoverflow.com/questions/3237727/what-does-predef-locally-do-and-how-is-it-different-from-predef-identity para obtener información sobre 'local'. –

Cuestiones relacionadas