Как финальный вал определяется внутри черты 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()
,