Scala 类标记和路径依赖类型,类似于蛋糕模式

Scala 类标记和路径依赖类型,类似于蛋糕模式,scala,types,path-dependent-type,cake-pattern,Scala,Types,Path Dependent Type,Cake Pattern,我正在从事一个光滑的项目,我正试图使我的数据库层在不同的配置文件之间轻松交换,以便在内存数据库上编写测试。这个问题的灵感来自于这个问题,但它与slick本身无关 我对依赖类型没有太多经验,在我的例子中,我有以下特点,用于从数据库中抽象出一些类型: trait Types { type A <: SomeType type B <: SomeOtherType val bTag: ClassTag[B] } 我需要该标记,因为稍后服务将需要它(在我的实际实现中,我使用该类

我正在从事一个光滑的项目,我正试图使我的数据库层在不同的配置文件之间轻松交换,以便在内存数据库上编写测试。这个问题的灵感来自于这个问题,但它与slick本身无关

我对依赖类型没有太多经验,在我的例子中,我有以下特点,用于从数据库中抽象出一些类型:

trait Types {
  type A <: SomeType
  type B <: SomeOtherType
  val bTag: ClassTag[B]
}
我需要该标记,因为稍后服务将需要它(在我的实际实现中,我使用该类型来抽象不同DB库引发的不同类型的异常);我确信有一个更好的方法来做我想做的事情

如果我没有实例化
ComponentTypes
trait以获取标记,并且我在DefaultBaseComponent中移动隐式变位代码,它将变位
null
,以代替
ClassTag
。我需要有一种方法来引用我正在使用的实际类型(我在不同环境中使用的不同
a
B
),并且我需要在其他组件中这样做,而不知道它们是什么实际类型

我的解决方案工作正常,编译并通过了我为它编写的所有测试,有人能帮我改进吗


谢谢大家!

对于所有这些
Default
s和
Component
s,您的示例有点不清楚-也许一个更具体的示例(例如DatabaseService/MysqlDatabaseService)会更清楚一些

你需要把
ClassTag
传递到任何抽象的地方——当你有一个具体的类型时,你只能“召唤”一个。您可能希望将值及其标记的概念打包:

trait TaggedValue[A] {val a: A; val ct: ClassTag[A]}
object TaggedValue {
  def apply[A: ClassTag](a1: A) =
    new TaggedValue[A] {
      val a = a1
      val ct = implicitly[ClassTag[A]]
    }
}
但这只是一件方便的事情。您还可以将一些
trait
s转换为
抽象类
es,允许您使用
[A:ClassTag]
隐式传递标记,但显然这会影响您可以多次继承的类

如果你点击了
null
s,听起来像是特征初始化顺序的问题,但是如果没有更具体的错误消息,就很难提供帮助。您可以通过将部分
val
s替换为
def
s,或者使用早期初始化程序来解决此问题

trait DefaultTypes {
  type A = SomeConcreteType
  type B = SomeOtherConcreteType
  val bTag = implicitly[ClassTag[B]]
}

trait DefaultBaseComponent extends BaseComponent {
  type ComponentTypes = DefaultTypes
  val ct = new ComponentTypes {}

  implicit val bTag = ct.bTag
}
trait TaggedValue[A] {val a: A; val ct: ClassTag[A]}
object TaggedValue {
  def apply[A: ClassTag](a1: A) =
    new TaggedValue[A] {
      val a = a1
      val ct = implicitly[ClassTag[A]]
    }
}