类型安全生成器:如何组合幻像类型 [英] Type-safe Builder: How to combine phantom types

查看:30
本文介绍了类型安全生成器:如何组合幻像类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在类型安全构建器模式中使用幻像类型来确保方法只调用一次,如下面的代码示例

I am using phantom types in the type-safe builder pattern to ensure methods are called only once as in the following code sample

  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 来链接方法调用(与其他方法不同)但是,如果有很多方法来保护以类似

I really appreciate this approach since one can use the .-operator to chain method calls (unlike with other approaches) However, this becomes unhandy if there are many methods to guard ending with something like

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

有没有办法创建类型结构"?类似于以下伪代码:

Is there a way to create a "type struct"? Something like the following pseudo code:

  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]
    }
  }

推荐答案

你走在正确的轨道上,你只需要添加一点类型细化:

You were on the right track, you just needed to add a little type refinement:

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
}

这篇关于类型安全生成器:如何组合幻像类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆