Как определить локальный 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 и не имеет значения за пределами области конструктора.

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

4 60

4 ответа:

например.

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

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

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

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

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

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

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

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

некоторые обсуждения на эту тему, в том числе комментарии Мартина Одерского,здесь