Как финальный вал определяется внутри черты Scala Compiler?

Я очень часто использую паттерн бескорыстной черты, и мне нужно использовать "дорогие" константы внутри черты: я хотел бы иметь один экземпляр этих значений, который может потребовать вычисления нескольких шагов во всех моих приложениях.

Однако модель самоотверженного поведения приводит к следующему дизайну:

  • Черта MyStuff
  • Объект MyStuff расширяет MyStuff

Очевидно, что помещение констант внутри объекта и использование их внутри черты создает циклическую зависимость. Однако размещение их в признаке позволяет всем классам, расширяющим признак, переопределять их, и, следовательно, они, безусловно, не являются синглтоном для всего приложения.

Является ли компилятор Scala "достаточно умным", чтобы сделать окончательные значения внутри черты "старым публичным java-статическим финалом"?

3 ответа

Нет, скала не переведет final val внутри черты, эквивалентной Java static final, поскольку final val должен быть членом экземпляра (не статическим членом) наследующего класса.

scala> trait myStuff { final val Test="test" }
defined trait myStuff

scala> class t extends myStuff
defined class t

scala> t.Test
<console>:8: error: not found: value t
              t.Test
              ^

// we need an instance of t to access Test
scala> new t
res2: t = t@35612600

scala> res2.Test
res3: String = test

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

//your expensive constant is here
scala> object MyConstant {final val C="C"}
defined module MyConstant

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait MyStuff {
import MyConstant._
def doStuff = C
}
object MyStuff extends MyStuff

// Exiting paste mode, now interpreting.

defined trait MyStuff
defined module MyStuff

// let's test importing the companion object of the selfless trait 
scala> import MyStuff._
import MyStuff._

scala> doStuff
res4: String = C

Какой пример циклической зависимости вы беспокоитесь?

Обычно это решается путем правильного использования определений в чертах или ленивых значений.

Вот пример проблемы, которая вызывается аргументами по умолчанию (которые синтезируются в объекте-компаньоне).

Но если вам нужно стремление, вы всегда можете определить заранее, определение:

scala> :pa
// Entering paste mode (ctrl-D to finish)

trait Foo {
  val v = 2 * Foo.w
}
object Foo extends {
  private val w = 3
} with Foo

// Exiting paste mode, now interpreting.

defined trait Foo
defined object Foo

scala> Foo.v
res11: Int = 6

Если расчет w использует члены FooТем не менее, вам придется пойти ленивым

trait Foo {
  val v = 2 * Foo.w
  def x = 7
}
object Foo extends Foo {
  lazy val w = 3 * x
}

Сегодня я второй раз спрашиваю об одном вопросе, но пока не искала его новый дом.

(Изменить: почему, вот оно.)

Как аналог public static final Вы должны использовать объект-компаньон, как это:

trait MyStuff
object MyStuff {
 val publicStaticFinal = ...
}

В этом случае scalac создает одноэлементный объект (public static final MyStuff$ MODULE$) с методом public int publicStaticFinal(), Вы могли бы сделать этот метод final если хотите.

За public final - использовать final val:

trait MyStuff
 final val publicFinal = ...
}

В этом случае scalac создает интерфейс с public abstract int publicFinal() и реализует его в каждом предке MyStuff как public final int publicFinal(),

Другие вопросы по тегам