ClassTag和路径依赖类型,类似于蛋糕图案的风格

时间:2014-08-06 16:54:37

标签: scala types path-dependent-type cake-pattern

我正在开发一个灵活的项目,我正在尝试使我的数据库层可以在不同的配置文件之间轻松交换,以便在内存数据库上编写测试。这个问题的灵感来自于这个问题,但它与光滑本身没有任何关系。

我对依赖类型没有太多经验,在我的情况下,我有以下特征用于从数据库中抽象出某些类型:

trait Types {
  type A <: SomeType
  type B <: SomeOtherType
  val bTag: ClassTag[B]
}

然后我有另一个特征基本上是我的(虚假)蛋糕模式的一部分:

trait BaseComponent {
  type ComponentTypes <: Types

  val a: Types#A
  implicit val bTag: ClassTag[Types#B]
}

然后我有一个实际的组件实现,可以看作如下:

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
}

我需要标记,因为稍后服务将需要它(在我的实际实现中,我使用此类型来抽象不同DB库抛出的不同类型的异常);我很确定有更好的方法可以做我想做的事情。

如果我没有实例化ComponentTypes特征以获取标记,并且我在DefaultBaseComponent中移动隐式变形代码,它将召唤null代替ClassTag 。我需要有一种方法来引用我正在使用的实际类型(我在不同环境中使用的AB)并且我需要在其他组件中执行它而不知道哪个它们的实际类型。

我的解决方案有效,编译并通过我为其编写的所有测试,任何人都可以帮我改进它吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

你的例子对于所有这些DefaultComponent来说有点不清楚 - 可能更具体的例子(例如DatabaseService / MysqlDatabaseService)会让它更清晰吗?

你需要将ClassTag传递给任何抽象的地方 - 你只能&#34;召唤&#34;一个具体的类型。您可能希望打包值及其标记的概念:

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转换为abstract class es,允许您使用[A: ClassTag]隐式传递标记,但这显然会影响您可以多次继承的类。

如果您点击null这听起来像是特质初始化订单问题,虽然没有更具体的错误消息,但很难提供帮助。您可以通过使用val替换某些def或使用早期初始值设定项来解决此问题。