Scala 类标记和路径依赖类型,类似于蛋糕模式
我正在从事一个光滑的项目,我正试图使我的数据库层在不同的配置文件之间轻松交换,以便在内存数据库上编写测试。这个问题的灵感来自于这个问题,但它与slick本身无关 我对依赖类型没有太多经验,在我的例子中,我有以下特点,用于从数据库中抽象出一些类型: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] } 我需要该标记,因为稍后服务将需要它(在我的实际实现中,我使用该类
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]]
}
}