我有一些代码具有不变量,即必须在最终使用的函数中构造对象(由于与全局状态相关的各种原因,这些原因并不理想但是是假设的一部分)。
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的返回值,或者它是否是事先创建的。
有许多方法可以在运行时验证这一点。但是,有没有办法在编译时强制使用此模式?使用暗示或其他任何聪明的东西?
感谢任何想法!
答案 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
。