2013-01-12 82 views
3

我使用幻象類型的類型安全的構建者模式,以確保方法被調用一次如下面的代碼樣本中類型安全生成器:如何設置編譯器錯誤消息

sealed trait TBoolean 
    sealed trait TTrue extends TBoolean 
    sealed trait TFalse extends TBoolean 

    class Builder[MethodCalled <: TBoolean] private() { 

    def foo()(implicit ev: MethodCalled =:= TFalse): Builder[TTrue] = { 
     new Builder[TTrue] 
    } 
    } 

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

Builder().foo().foo()不起作用根據需要,但是我想將錯誤消息設置爲用戶可讀的。此刻的消息是在該線

多個標記 - 不夠論據方法foo:(隱式EV:=:= [W.TTrue,W.TFalse])W.Builder [W.TTrue ]。未指定的值參數ev。 - 無法證明W.TTrue =:= W.TFalse。 - 無法證明W.TTrue =:= W.TFalse。

回答

5

這裏使用類型參數有點矯枉過正。更好距離foo方法返回能力較弱的類型:

object Builder { 
    trait CanFoo { def foo() : Builder } 
    def apply(): Builder with CanFoo = new Builder with CanFoo { 
    def foo() = new Builder {} 
    } 
} 
trait Builder 

Builder().foo().foo() // value foo is not a member of Builder 

有一個註釋implicitNotFound其中can be used定製錯誤消息,但它需要與所尋求的類型來定義(=:=)不使用的網站(foo),so that is a pretty useless construction ...

...除非你創建自己的替代=:=

import annotation.implicitNotFound 

object Called { 
    implicit def same[A]: Called[A, A] = instance.asInstanceOf[Called[A, A]] 
    private object instance extends Called[Any,Any] 
} 
@implicitNotFound(msg = "Cannot call this method twice") sealed trait Called[A, B] 

class Builder[Foo <: TBoolean] private() { 
    def foo()(implicit ev: Called[Foo, TFalse]): Builder[TTrue] = { 
    new Builder[TTrue] 
    } 
} 
object Builder { 
    def apply() = new Builder[TFalse]() 
} 

Builder().foo().foo() // -> "error: Cannot call this method twice" 
+0

可能會謹慎地稱呼'NotCalled'特性而不是'Called'。否則,偉大的職位+1。 –

+0

它代表已被調用的方法,因此不適合再次調用。這個名字似乎適合我。 –

+0

或使用類型別名'type NotCalled [A] = Called [A,TFalse]' –

2

您不能自定義錯誤消息,但您可以可以自定義您的特徵名稱。我會打電話給他們BuiltUnbuilt或類似的東西。然後,您可以警告圖書館的用戶或任何您會看到毛茸茸的錯誤消息的用戶,但他們只需要找到類似Cannot prove that Built =:= Unbuilt的東西。

相關問題