Scala 向列表中添加元素时的编译时类型检查

Scala 向列表中添加元素时的编译时类型检查,scala,types,Scala,Types,是否可以在编译时使用Scala实现它 用例: API用户试图建立一个事物的列表 一旦用户添加了ComplexThing的子类,就不允许添加任何其他内容 在运行时检查很容易,有什么解决方案可以在编译时实现它吗? 目标是使IDE突出显示编译错误 trait Thing trait SimpleThing extends Thing trait ComplexThing extends Thing sealed case class DummySimpleThing() extends S

是否可以在编译时使用Scala实现它

用例:

  • API用户试图建立一个
    事物的列表
    
  • 一旦用户添加了
    ComplexThing
    的子类,就不允许添加任何其他内容
在运行时检查很容易,有什么解决方案可以在编译时实现它吗? 目标是使IDE突出显示编译错误


trait Thing

trait SimpleThing extends Thing

trait ComplexThing extends Thing

sealed case class DummySimpleThing() extends SimpleThing

sealed case class InstanceOfComplexThing() extends ComplexThing

class ThingRepository {
  private val buffer = new ListBuffer[Thing]()

  def addThing(thing: Thing): ThingRepository = {
    buffer += thing
    this
  }
}

object TestThingRepository {

  def testAddThings() = {
    new ThingRepository()
      .addThing(DummySimpleThing())
      .addThing(DummySimpleThing()) // it's ok to add SimpleThing after SimpleThing
      .addThing(InstanceOfComplexThing()) // it's ok to add ComplexThing after SimpleThing

      .addThing(DummySimpleThing()) // Not allowed to add anything after ComplexThing, how can I get compile time error here?
      .addThing(InstanceOfComplexThing()) // Not allowed anything after ComplexThing, how can I get compile time error here?
  }
}

对于可变存储库,您无法做到这一点,因为一旦定义了类,就无法更改它的签名

如果
addThing
返回了一个新的存储库,则可以执行此操作,因为添加
ComplexThing
可以返回一个没有
addThing
方法的存储库,而添加
SimpleThing
则返回一个带有
addThing
方法的存储库

case class StaticThingRepository(buffer: List[Thing])

class ThingRepository private(buffer: List[Thing]) {  
  def addThing(thing: Thing): ThingRepository =
    new ThingRepository(buffer :+ thing)

  def addThing(thing: ComplexThing): StaticThingRepository =
    StaticThingRepository(buffer :+ thing)
}

object ThingRepository {
  def apply() = new ThingRepository(Nil)
}

对于可变存储库,您无法做到这一点,因为一旦定义了类,就无法更改它的签名

如果
addThing
返回了一个新的存储库,则可以执行此操作,因为添加
ComplexThing
可以返回一个没有
addThing
方法的存储库,而添加
SimpleThing
则返回一个带有
addThing
方法的存储库

case class StaticThingRepository(buffer: List[Thing])

class ThingRepository private(buffer: List[Thing]) {  
  def addThing(thing: Thing): ThingRepository =
    new ThingRepository(buffer :+ thing)

  def addThing(thing: ComplexThing): StaticThingRepository =
    StaticThingRepository(buffer :+ thing)
}

object ThingRepository {
  def apply() = new ThingRepository(Nil)
}

通常情况下,您只有
密封的
特征,如果有任何特征,则案例类将成为最终的
。这里有很好的解释:通常情况下,您只会拥有
密封的
特征,如果有任何特征,那么案例类将成为
最终的
。这里有很好的解释: