3

次のコードサンプルのように、メソッドが1回だけ呼び出されるように、タイプセーフビルダーパターンでファントムタイプを使用しています。

  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であることを証明できません。

4

2 に答える 2

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ますが、それは使用サイト()ではなく、求められているタイプ()で定義する必要があるため、かなり役に立たない構造です...=:=foo

...独自の代替品を作成しない限り=:=

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"
于 2013-01-12T12:09:30.273 に答える
2

エラーメッセージをカスタマイズすることはできませんが、トレイト名をカスタマイズすることはできます。私はそれらとかそのようなものBuiltと呼ぶでしょう。Unbuilt次に、ライブラリのユーザーや、毛むくじゃらのようなエラーメッセージが表示されることをユーザーに警告できますが、実際には、のようなものを見つけるだけで済みますCannot prove that Built =:= Unbuilt

于 2013-01-12T11:55:04.080 に答える