首页 文章

使用泛型和案例类方法的Scala特征

提问于
浏览
2

我有以下情况/代码;

trait Model {
    def myField: String
}

case class MyModel(myField: String) extends Model

在为我的模型类创建DAO的传统模型中,我想创建一个包含一些通用CRUD操作的DAO特征 . 注意......持久性框架在这里并不重要......问题是在使用泛型的特征中使用案例类方法 .

据说我想创造以下特质;

trait DAO[M <: Model] {
   def insert(model: M): M = {
     ... do work
     m.copy(myField="someval")
   }
}

在这种情况下,代码不会编译,因为泛型M对“案例类”一无所知 . 如果这里有一些简单的解决方案,可以将泛型声明为需要成为一种案例吗?或者Model trait是否应该声明一个任何扩展类必须实现的复制方法,并且它是一个case类吗?

1 回答

  • 7

    如果这里有一些简单的解决方案,可以将泛型声明为需要成为一种案例吗?

    没有 .

    或者模型特征是否应该声明一个任何扩展类必须实现的复制方法,并且它是一个案例类呢?

    不幸的是,也没有 . 抽象 copy 方法由于两个原因不起作用 .

    首先,如果在特征中声明一个抽象的 copy 方法,它实际上会阻止扩展它的case类自动生成它,并且你不得不自己实现它 .

    其次,很难要求这样的通用方法 . 我的意思是,当您声明一个抽象方法时,您需要指定完整的签名 . 但是,可以假设所有扩展 Model 的案例类都不会具有相同的签名,因此它们不能具有相同的 copy 方法 . 它不能那样工作 .

    不幸的是,您需要自己为子类实现类似的方法 . 我使用F-bounded多态来填充 id

    trait Model[M <: Model[M]] { this: M =>
        def id: Option[Long]
        def withId(id: Long): M
    }
    
    case class MyModel(id: Option[Long], ...) extends Model[MyModel] {
        def withId(id: Long): MyModel = this.copy(id = Some(id))
    }
    
    trait DAO[M <: Model[M]] {
       def insert(model: M): M = {
         ... do work
         m.withId(someGeneratedId)
       }
    }
    

    重复代码的一点点很难看,但足以让人忍受 . 也许有可能用反射或宏来做这样的事情,但这可能不是简单的事情 .

相关问题