Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 是否可以更新实现公共特征的任何案例类的字段_Scala_Case Class_Shapeless - Fatal编程技术网

Scala 是否可以更新实现公共特征的任何案例类的字段

Scala 是否可以更新实现公共特征的任何案例类的字段,scala,case-class,shapeless,Scala,Case Class,Shapeless,让我们假设我们有一个共同特征模型 trait Model { def id: String def updated: Date } 我们有两个案例类扩展了这个特性 case class C1(id: String, updated: Date, foo: String) extends Model case class C2(id: String, updated: Date, bar: Int) extends Model 是否可以编写下面这样的实用程序函数,将模型作为参数并返回一

让我们假设我们有一个共同特征模型

trait Model {
  def id: String
  def updated: Date
}
我们有两个案例类扩展了这个特性

case class C1(id: String, updated: Date, foo: String) extends Model
case class C2(id: String, updated: Date, bar: Int) extends Model
是否可以编写下面这样的实用程序函数,将模型作为参数并返回一个副本,其中包含更新字段的更新值

object Model {
    def update[T <: Model](model: T): T = {
        model.copy(updated = new Date) // This code does not compile.
    }
}
对象模型{

def update[T
copy
是在您的案例类上定义的方法。而不是在您的基本trait
模型上定义的方法。如果您有:

trait Model {
  def id: String
  def updated: Date
}

case class C1(id: String, updated: Date, foo: String) extends Model
case class C2(id: String, updated: Date, bar: Int) extends Model
class NotACaseClass(val id: String, val updated: Date) extends Model 

notacesclass
Model
的一个非常有效的子类,您可以将它的一个实例传递给您的
update
函数,但是祝您好运找到一个
copy
方法:)

您的代码有两个问题:

  • copy
    没有在trait上定义,因此您需要在trait上定义一些可以使用的内容
  • 为了使
    update
    返回
    T
    而不是
    Model
    ,每个
    Model
    必须知道其实际的子类型
  • 您可以这样修复它:

    trait Model[T <: Model[T]] {
      def id: String
      def updated: Date
      def withDate(d: Date): T
    }
    
    case class C1(id: String, updated: Date, foo: String) extends Model[C1] { def withDate(d: Date) = copy(updated = d) }
    case class C2(id: String, updated: Date, bar: Int)    extends Model[C2] { def withDate(d: Date) = copy(updated = d) }
    
    object Model {
      def update[T <: Model[T]](model: T): T = {
        model.withDate(new Date) // This code does not compile.
      }
    }
    
    您可以在这里编写的“最佳”抽象是
    镜头
    ,它看起来像:

    trait Lens[A, B]{
      def get: A => B
      def set: (A, B) => A
    }
    
    def update[A](that: A, value: Date)(implicit tLens: Lens[A, Date]): A =
      tLens set (that, value)
    
    因此,您的代码如下所示:

    trait Lens[A, B]{
      def get: A => B
      def set: (A, B) => A
    }
    
    def update[A](that: A, value: Date)(implicit tLens: Lens[A, Date]): A =
      tLens set (that, value)
    

    @米利萨宾,但这种过度工程几乎不是一个可行的选择(现在,你可以随意称我为“有偏见的”甚至是白痴:-))。或者除此之外还有其他方法吗?它回答了为什么它不起作用,但对给定的问题没有提供解决方案。镜头是好的……但我想我们可能可以推断出给定一个不成形的
    LabelledGeneric
    的镜头用于所讨论的案例类。@MilesSabin是的,我打赌你是对的。如果你写它,我会把这个答案给你。这是这是我计划采用的方法。但我仍然想知道是否有一种方法可以自动完成这项工作并确保键入安全。因此,即使
    withDate
    的每个子类型的
    Model
    都有相同的代码行,但每个类都需要重写,对吗?