我经常使用无私特质模式,我需要在特质中使用"昂贵"的常量:我希望在我的所有应用程序中都有这些值的一个实例,这可能需要计算几个步骤。
然而,无私的特质模式导致了以下设计:
- 一种特质MyStuff
- 对象MyStuff扩展MyStuff
很明显,将常量放入对象中并在特性中使用它们会产生循环依赖关系。然而,将它们放在trait上,使得所有扩展trait的类都有可能覆盖它们,因此它们肯定不是应用程序范围内的单例。
Scala编译器是否"足够聪明",可以使特性中的最终val变成"旧的java公共静态final"?
不,scala不会将trait中的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
如果你正在使用无私特质,而你不能将你的最终价值存储在MyStuff的同伴对象中(因为你在特质本身中使用它),你可能只需要为你的最终值创建另一个对象。
//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
您关心的循环依赖关系的示例是什么?
通常,这是通过在特质或懒惰vals中适当使用defs来解决的。
下面是一个由默认args(在伴随对象中合成)引发的示例问题。
但如果你需要渴望,你可以尽早定义,définition en avance:
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 int publicStaticFinal()
创建一个单例对象(public static final MyStuff$ MODULE$
)。如果你想的话,你可以把这个方法做成final
对于public final
,使用final val
:
trait MyStuff
final val publicFinal = ...
}
在这种情况下,scalac
创建了一个与public abstract int publicFinal()
的接口,并在MyStuff
的每个祖先中将其实现为public final int publicFinal()
。