2

我经常使用无私的特征模式,并且我需要在特征中使用“昂贵的”常量:我希望在我的所有应用程序中拥有这些值的单个实例,这可能需要计算几个步骤。

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

  • 一个特质 MyStuff
  • 一个对象 MyStuff 扩展了 MyStuff

显然,将常量放在对象中并在 trait 中使用它们会产生循环依赖。然而,将它们放在 trait 上,使得所有扩展 trait 的类都可以覆盖它们,因此它们肯定不是应用程序范围的单例。

Scala 编译器是否“足够聪明”以使特征中的最终 val 变为“旧的 java public static final”?

4

3 回答 3

3

不,scala 不会将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 的伴生对象中(因为你在 trait 本身中使用它),你可能只是为你的最终 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
于 2013-12-06T09:08:39.680 回答
1

你关心的循环依赖的例子是什么?

通常这是通过在 trait 或惰性 val 中适当使用 defs 来解决的。

这是一个由默认参数(在伴随对象中合成)引起的示例问题。

但如果你需要热切,你总是可以提前定义,提前定义

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
}

这是我今天第二次需要一个问题的常见问题解答,但我还没有寻找它的新家。

(编辑:为什么,在这里。)

于 2013-12-06T10:45:40.103 回答
-1

作为您的模拟,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,创建一个接口并在aspublic abstract int publicFinal()的每个祖先中实现它。MyStuffpublic final int publicFinal()

于 2013-12-06T08:49:57.630 回答