Как определить локальный 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)
  }
}

Ответ 2

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

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

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

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

Ответ 3

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

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

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

Ответ 4

Некоторая дискуссия по этой теме, включая комментарии Мартина Одерского, здесь