如何在Scala编译器处理的特征中定义最终值?

时间:2013-12-06 08:41:37

标签: scala scalac scala-compiler

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

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

  • 特质MyStuff
  • 对象MyStuff扩展MyStuff

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

Scala编译器“足够聪明”使特征中的最终值成为“旧的Java公共静态最终版”吗?

3 个答案:

答案 0 :(得分: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

如果您使用无私特质,并且无法在MyStuff的伴侣对象中存储您的最终val(因为您在特质本身中使用它),您可能只是为你的最终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

答案 1 :(得分:1)

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

通常通过在特质或懒惰中适当使用defs来解决这个问题。

这是默认args引起的an example issue(在伴侣对象中合成)。

但如果你需要急切,你可以随时定义définitionenavance

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
}

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

(编辑:为什么,here it is。)

答案 2 :(得分:-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会创建一个包含public abstract int publicFinal()的界面,并在MyStuff的每个祖先中将其作为public final int publicFinal()实现。