Scala编译器如何在特性中定义最终val



我经常使用无私特质模式,我需要在特质中使用"昂贵"的常量:我希望在我的所有应用程序中都有这些值的一个实例,这可能需要计算几个步骤。

然而,无私的特质模式导致了以下设计:

  • 一种特质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()

相关内容

  • 没有找到相关文章

最新更新