2011-09-09 44 views
8

我有一些代碼具有必須在最終使用它的函數中構造一個對象的常量(出於與全局狀態相關的各種原因,這些原因並不理想但是是部分的假設)。Scala編譯時檢查構造函數調用的位置

例如假設下面的函數boo負責操作moo。希望使用布布的

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

客戶端必須通過在一個類型()=>武,其中函數產生期望武的。

理想的客戶端的行爲:

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

も沒有,直到噓體內產生。

但是,客戶端可以很容易地用下面的代碼失誤:

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

這打破了我們想要只發生在噓も結構不變。

所以基本上,我想確定mooGen的返回值是在函數的調用堆棧中創建的,還是事先創建的。

有很多方法可以在運行時驗證它。但是,有沒有辦法強制這個模式在編譯時間?使用implicits或其他聰明的東西?

任何想法感謝!

回答

12

將噓聲和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]) 
3

我想如果Moo兩個構造函數和方法boo是你的控制之下,並且不需要客戶端寫的,那麼你可以讓Moo採取的隱含參數,並安排了唯一的地方,一個合適的隱含值範圍在boo

這並不理想......並且您可能無法使隱式參數的類型完全保密(這會使得客戶端不會在boo之外實例化Moo),因爲我懷疑編譯器會抱怨在Moo的定義中泄漏的私有類型。但即使沒有這一點,它應該至少可以幫助您在boo之外防止意外Moo的創建;客戶必須刻意獲得一個隱含的價值,以允許他們創建Moo