Scala编译时间检查构造函数调用的位置

时间:2011-09-09 05:58:50

标签: scala

我有一些代码具有不变量,即必须在最终使用的函数中构造对象(由于与全局状态相关的各种原因,这些原因并不理想但是是假设的一部分)。

e.g。假设下面有函数boo负责操作moo。

def boo(mooGen: () => Moo) {
  val m = mooGen() // a new MOO must be created HERE
  m.moo()
}

想要使用boo的boo客户端必须传入一种()=> Moo,函数生成所需的Moo。

理想的客户行为:

boo( () => new Moo(// specific parameters here) )

直到嘘声体内才会创造Moo。

但是,客户端很容易使用以下代码进行错误处理:

val myMoo = new Moo(// specific parameters here)
boo( () => myMoo)

这打破了我们希望moo构造仅在boo中发生的不变量。

所以基本上,我想确定是否在函数的调用堆栈中创建了mooGen的返回值,或者它是否是事先创建的。

有许多方法可以在运行时验证这一点。但是,有没有办法在编译时强制使用此模式?使用暗示或其他任何聪明的东西?

感谢任何想法!

2 个答案:

答案 0 :(得分:12)

将boo和Moo与Token类一起放入自己的对象中,无法在对象外实例化。

scala> object Foo {
     | class Moo(token:Token) {}
     | class Token private[Foo]()
     | def boo(mooGen: (Token) => Moo) {val m = mooGen(new Token)}
     | }
defined module Foo

现在可以做到:

scala> Foo.boo(new Foo.Moo(_))

你不想做的事情无法完成:

scala> val mymoo = new Foo.Moo(new Foo.Token)
<console>:8: error: constructor Token in class Token cannot be accessed in objec
t $iw
       val mymoo = new Foo.Moo(new Foo.Token)
                           ^

但如果客户真的想要他可以 - 不幸的是 - 仍然得到他的Moo:

val ireallywantone = new Foo.Moo(null.asInstanceOf[Foo.Token])

答案 1 :(得分:3)

我想如果Moo的构造函数和方法boo都在您的控制之下,并且不需要由客户编写,那么您可以让Moo隐式参数,并安排合适的隐含值在范围内的唯一位置是boo

它并不理想......并且您可能无法使隐式参数的类型完全隐私(这会使客户端不会在Moo之外实例化boo {1}}),因为我怀疑编译器会在Moo的定义中抱怨私有类型泄漏。但即使没有它,它至少应该帮助您防止在Moo之外意外创建boo;客户端必须故意获取隐含值,以允许他们创建Moo