Как определить локальный var/val в первичном конструкторе в Scala?

В Scala первичный конструктор класса не имеет явного тела, а определяется неявно из тела класса. Как тогда отличить поля от локальных значений (т.е. значений, локальных для метода конструктора)?

Например, возьмем следующий фрагмент кода, представляющий собой модифицированную форму примера кода из "Программирования на Scala":

class R(n: Int, d: Int) {
   private val g = myfunc
   val x = n / g
   val y = d / g
}

Насколько я понимаю, это создаст класс с тремя полями: приватным "g" и публичными "x" и "y". Однако значение g используется только для вычисления полей x и y и не имеет никакого значения за пределами конструктора.

Итак, в этом (безусловно, искусственном) примере, как вы собираетесь определить локальные значения для этого конструктора?

Комментарии к вопросу (1)
Решение

Например.

class R(n: Int, d: Int) {
  val (x, y) = {
    val g = myfunc
    (n/g, d/g)
  }
}
Комментарии (4)

Есть несколько способов сделать это. Вы можете объявить такие временные переменные внутри частных определений, которые будут использоваться во время конструирования. Можно использовать временные переменные внутри блоков, возвращающих выражения (как в ответе Alaz'). Или, наконец, вы можете использовать такие переменные внутри альтернативных конструкторов.

По аналогии с альтернативными конструкторами, вы также можете определить их внутри метода "apply" объекта-компаньона.

Что вы не можете сделать, так это объявить поле "временным".

Заметьте также, что любой параметр, полученный первичным конструктором, также является полем. Если вы не хотите, чтобы такие параметры становились полями, и не хотите раскрывать фактические поля в конструкторе, обычным решением будет сделать первичный конструктор приватным, с фактическими полями, и использовать либо альтернативный конструктор, либо объект-компаньон apply() в качестве эффективного "первичного" конструктора.

Комментарии (0)

Другой вариант-сделать основной конструктор объекта частная и использовать компаньон объекта'ь применять метод в качестве строителя. Если мы применим (каламбур не предназначен) этот подход в вашем примере это будет выглядеть так:

class R private (val x: Int, val y: Int);

object R {
  def apply(n: Int, d: Int): R = {
    val g = myfunc;
    new R(n / g, d / g);
  }
}

Для создания экземпляра R вместо:

val r = new R(1, 2);

пишите:

val r = R(1, 2);

Это немного многословный, но могло быть и хуже, я думаю :). Позвольте's надеюсь, что частные[это] вальс будет рассматриваться как временные переменные в будущих выпусках Скала. Сам Мартин намекал, что.

Комментарии (2)

Некоторые дискуссии на эту тему, включая комментарии Martin Odersky'a, находятся здесь.

Комментарии (2)