【问题标题】:Scala traits using generics and case class methods使用泛型和案例类方法的 Scala 特征
【发布时间】:2015-02-19 01:45:07
【问题描述】:

我有以下情况/代码;

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 是否应该声明一个任何扩展类都必须实现的复制方法,并且作为一个案例类来实现它?

【问题讨论】:

  • 这能回答你的问题吗?

标签: scala generics case-class


【解决方案1】:

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

没有。

或者 Model trait 是否应该声明一个任何扩展类都必须实现的复制方法,并且作为一个案例类来实现它?

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

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

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

不幸的是,您需要自己为子类实现类似的方法。我使用 F 有界多态性来填充ids:

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)
   }
}

重复的代码很难看,但足以忍受。也许可以通过反射或宏来做这样的事情,但这可能绝非简单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-02
    • 2014-09-23
    • 1970-01-01
    • 1970-01-01
    • 2011-03-17
    • 2023-04-03
    • 1970-01-01
    • 2016-11-26
    相关资源
    最近更新 更多