Можно ли определить локальную переменную конструктора в Scala? - PullRequest
10 голосов
/ 13 января 2012

Следующий код взят из книги «Программирование в 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)
}

Здесь значение g используется только тогда, когда неявный конструктор инициализирует поля numer и denom. Предположим, программист знает, что он не будет использоваться где-либо еще. В приведенном выше случае он все еще доступен после постройки объекта Rational. Это означает, что он также будет занимать пространство, поскольку является частным полем, а не локальной переменной для конструктора.

У меня вопрос, как мне изменить этот код, чтобы g использовался только во время создания, а затем выбрасывался?

1 Ответ

10 голосов
/ 13 января 2012

В таком случае, как насчет чего-то подобного?

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

РЕДАКТИРОВАТЬ: Это также создает дополнительное поле, которое содержит кортеж, как показано при запуске javap в скомпилированном классе (спасибо, Алексей):

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

В других случаях я иногда использую блок locally, чтобы не превращать каждый val в поле:

class A {
  locally {
    val value1 = // ...
    val value2 = // ...
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...