更新时间:2022-01-03 09:05:37
你走在正确的轨道上,你只需要添加一点类型细化:
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
}