2

次のコード サンプルのように、メソッドが 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]()
  }

.-operator を使用してメソッド呼び出しをチェーンできるため、このアプローチを本当に高く評価しています (他のアプローチとは異なります)。

  class Builder[MethodCalled1 <: TBoolean, MethodCalled2 <: TBoolean, ... ,MethodCalledN <: TBoolean]

「型構造体」を作成する方法はありますか? 次の擬似コードのようなもの:

  type S {
      type MethodCalled1 <: TBoolean
      type MethodCalled2 <: TBoolean
      ...
      type MethodCalledN <: TBoolean
  }

  class Builder[S] private() {

    def foo()(implicit ev: S#MethodCalled1 =:= TFalse): Builder[S#MethodCalled1.TTrue] = {
      new Builder[S#MethodCalled1.TTrue]
    }
  }
4

1 に答える 1

5

あなたは正しい方向に進んでいました。ちょっとしたタイプの改良を加える必要がありました。

trait BuilderMethods {
  type FooCalled <: TBoolean
  type BarCalled <: TBoolean
}

class Builder[M <: BuilderMethods] private() {
  def foo()(implicit ev: M#FooCalled =:= TFalse): Builder[M {type FooCalled = TTrue}] = {
    new Builder[M {type FooCalled = TTrue}]
  }
  def bar()(implicit ev: M#BarCalled =:= TFalse): Builder[M {type BarCalled = TTrue}] = {
    new Builder[M {type BarCalled = TTrue}]
  }
}

object Builder {
  type UnusedBuilder = BuilderMethods {type FooCalled = TFalse; type BarCalled = TFalse;}
  def apply(): Builder[Builder.UnusedBuilder] = new Builder[UnusedBuilder]()
}

object TestPhantomStruct extends App {
  val newBuilder = Builder()
  val builderFooCalled = newBuilder.foo()
  val builderFooCalledTwice = builderFooCalled.foo() // will not compile
  val builderFooCalledBarCalled = builderFooCalled.bar()
  val builderFooCalledTwiceBarCalled = builderFooCalledBarCalled.foo() // will not compile

  val builderBarCalled = newBuilder.bar()
  val builderBarCalledTwice = builderBarCalled.bar() // will not compile
}
于 2013-01-11T20:14:45.410 に答える