简体   繁体   English

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

[英]Scala traits using generics and case class methods

I have the following situation/code; 我有以下情况/代码;

trait Model {
    def myField: String
}

case class MyModel(myField: String) extends Model

In the traditional model of creating DAOs for my model classes I want to create a DAO trait that contains some generic CRUD operations. 在为我的模型类创建DAO的传统模型中,我想创建一个包含一些通用CRUD操作的DAO特征。 NOTE...the persistence framework doesn't matter here...the question is around using case class methods within a trait that is using generics. 注意......持久性框架在这里并不重要......问题是在使用泛型的特征中使用案例类方法。

With that said I want to create the following trait; 据说我想创造以下特质;

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

In this case the code does not compile because generic M knows nothing about being a "case class". 在这种情况下,代码不会编译,因为泛型M对“案例类”一无所知。 If there some easy solution here, can a generic be declared as needing to be a type of case? 如果这里有一些简单的解决方案,可以将泛型声明为需要成为一种案例吗? Or should the Model trait declare a copy method that any extending class has to implement and by being a case class it does so? 或者Model trait是否应该声明一个任何扩展类必须实现的复制方法,并且它是一个case类吗?

If there some easy solution here, can a generic be declared as needing to be a type of case? 如果这里有一些简单的解决方案,可以将泛型声明为需要成为一种案例吗?

No. 没有。

Or should the Model trait declare a copy method that any extending class has to implement and by being a case class it does so? 或者Model trait是否应该声明一个任何扩展类必须实现的复制方法,并且它是一个case类吗?

Unfortunately, also no. 不幸的是,也没有。 An abstract copy method won't work for two reasons. 抽象copy方法不会有两个原因。

First, if you declare an abstract copy method in your trait, it will actually prevent the case class that extends it from automatically generating it, and you're forced to implement it yourself. 首先,如果您在特征中声明了一个抽象copy方法,它实际上会阻止扩展它的案例类自动生成它,并且您不得不自己实现它。

Second, it's hard to require such a generic method such as that. 其次,很难要求像这样的通用方法。 What I mean is, when you declare an abstract method, you need to specify the full signature. 我的意思是,当您声明一个抽象方法时,您需要指定完整的签名。 However, one would assume that all case classes that extend Model will not have the same signatures, so they cannot have the same copy method. 但是,可以假设扩展Model所有案例类都不具有相同的签名,因此它们不能具有相同的copy方法。 It just can't work that way. 它不能那样工作。

Unfortunately that leaves you with needing to implement similar methods yourself for sub-classes. 不幸的是,您需要自己为子类实现类似的方法。 I do this sort of thing filling id s using F-bounded polymorphism: 我做这种事情使用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)
   }
}

The bit of repeated code is ugly, but enough to live with. 重复代码的一点点很难看,但足以让人忍受。 Perhaps it may be possible to do something like this with reflection or a macro, but that would likely be anything but simple. 也许有可能用反射或宏来做这样的事情,但这可能不是简单的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM