2013-07-26 77 views
6

的重複我想要實現方法鏈接像這些問題:類型安全的方法鏈接不允許操作

Best practice to implement Scala trait which supports method chaining;

Scala DSL: method chaining with parameterless methods

不過,我想,一旦「屬性」已被使用,無法再使用。 例如,假設我有一個類「Myclass」,我希望最多允許使用定義「foo」和定義「bar」一次,而我不關心最終返回類型。因此:

val c = new Myclass 
c foo //ok ! 
c foo bar // ok! 
c foo foo // refuse to compile 
c foo bar foo //refuse to compile 

我一直在努力解決這個問題,我的視力開始變得模糊! 我試圖使用隱式類,但是,他們是否需要分析沒有使用關聯屬性的對象,並且我無法找到它們是否需要通過從可用對象中刪除屬性來「消耗」屬性財產,而且,我再也找不到如何。

我目前在反射API中搜索,但對我來說還是有點模糊。

幫助,將不勝感激! =)

回答

14

請參閱Phantom Types In Haskell and Scala通過James Iry

你也可以使用類型安全的構建者模式:

trait TTrue 
trait TFalse 

@annotation.implicitNotFound(msg = "Cannot call same method twice.") 
sealed abstract class =^=[From, To] 
object =^= { 
    private val singleton_=^= = new =^=[Any, Any]{} 
    implicit def tpEquals[A]: A =^= A = singleton_=^=.asInstanceOf[A =^= A] 
} 

class Myclass[TFoo, TBar, TBuz] private(){ 
    def foo(implicit e: TFoo =^= TFalse) = new Myclass[TTrue, TBar, TBuz] 
    def bar(implicit e: TBar =^= TFalse) = new Myclass[TFoo, TTrue, TBuz] 
    def buz(implicit e: TBuz =^= TFalse) = new Myclass[TFoo, TBar, TTrue] 
} 

object Myclass{ 
    def apply() = new Myclass[TFalse, TFalse, TFalse] 
} 

使用這樣

scala> Myclass().foo.bar.buz 
res0: Myclass[TTrue,TTrue,TTrue] = [email protected] 

scala> Myclass().bar.buz.foo 
res1: Myclass[TTrue,TTrue,TTrue] = [email protected] 

scala> Myclass().foo.buz.foo 
<console>:12: error: Cannot call same method twice. 
       Myclass().foo.buz.foo 
           ^
+0

+1類型建設者。但是這個實現與方法的數量緊密相關,如何添加10個新方法?而這樣的生產中的錯誤將是奇怪的 – 4lex1v

+0

@AlexIv:對於10個方法,你將不得不添加10個類型參數。修正了錯誤消息。這是一個編譯錯誤,而不是運行時生成錯誤。 – senia

+1

謝謝你的回答。我明白了主要想法:對於激活選項時切換的每個選項,都有一個TTrue/TFalse標誌。爲了在編譯時檢測一個選項的激活,你要求隱式實例化一個對象,當且僅當該標誌具有正確的值時才能隱式地實例化該對象。因此,如果選項已被調用,則標誌爲真,隱式實例是不可能的,編譯器通過在註釋中拋出測試失敗。我認爲這是一個非常優雅的解決方案。 –

相關問題