0

我试图构建一个用任一类型的具体类实例化的通用 DAO:

  1. 常规的
  2. 活泼的<:常规

我目前有一个描述可用方法的 trait DAO,get/create/upsert。在编译时,我想根据我传递的类型参数更改/定义每个方法。这是一些代码:

trait Regular {
    id: int
}

trait Snap extends Regular {
    isSnappy: Boolean = true
}

trait DAO[T<: Regular] {
  def get(id: String)(implicit x: Param,ct: ClassTag[T]): Future[Either[String, T]] 
}

如果特征是常规的:

 def get(id:String)(implicit x: Param,ct: ClassTag[T]): Future[Either[String, T]] = {
   //Handle regular trait flow
 }

如果特征是 Snap <: 常规:

 def get(id:String)(implicit x: Param,ct: ClassTag[T]): Future[Either[String, T]] = {
   //Handle snappy
 }

两个 def 将返回相同的类型 T。

我希望能够在编译时更改 def,我知道 DAO 中的 Type 参数。然后在运行时我希望能够实例化该类,但让它根据传递的类型处理 def。

我不确定如何在 scala 中处理这个问题,无论它是基于宏的解决方案、重载方法还是为 Dao 定义的某种类型的隐式。任何方向将不胜感激!我不确定这是否是一个独特的问题,但我已经尽可能多地阅读了基于类型参数的编译时间定义,同时仍然能够引用相同的特征(在这种情况下为 DAO)

4

1 回答 1

1

对于这种情况,您可能需要一个类型类。有很多关于这方面的内容要阅读,但这里有一个基于您的代码的精简版本的示例。

首先定义一个包含所有所需操作的类:

trait DaoOps[T] {
  def get(id: String): Int
  def create(id: String): T
  def upsert(id: String): Int
}

然后为每种类型创建一个具有实现的implicit实例:DaoOps

trait Regular {
    def id: Int
}

object Regular {
  // DAO implementation for instances of Regular type
  implicit object dao extends DaoOps[Regular] {
    def get(id: String): Int = ???
    def create(id: String): Regular = ???
    def upsert(id: String): Int = ???
  }
}

trait Snap extends Regular {
  def isSnappy: Boolean = true
}

object Snap {
  // DAO implementation for instances of Snap type
  implicit object dao extends DaoOps[Snap] {
    def get(id: String): Int = ???
    def create(id: String): Snap = ???
    def upsert(id: String): Int = ???
  }
}

最后,使用主类中的 typeclass 来选择正在使用的特定类型的实现:

trait DAO[T <: Regular] {
  // Select the ops for the actual type of T
  def get(id: String)(implicit ops: DaoOps[T]): Int =
    ops.get(id)
}

implicit objects 不必在伴生类中,但编译器会在那里查找它们,以避免必须显式地将它们带入范围。

于 2021-07-01T16:51:45.013 回答