Scala - 使用动态字段复制大小写 class。可能吗?

Scala - copy case class with dynamic fields. Is it possible?

考虑到案例 class 在创建时计算了默认字段,是否可以在新复制的案例 class 重新计算该字段的地方复制它?

例如TestCopy.auto在创建时生成:

  case class TestCopy(static: String, auto: Long = System.currentTimeMillis()) {
    val auto2 = System.currentTimeMillis()
  }

如果我复制它只改变字段 static:

    val a = TestCopy(static = "a")
    val b = a.copy(static = "b")

字段 auto 未重新计算。构造函数字段 auto2:

也不是
> println(a)
> println(b)
> println(a.auto2)
> println(b.auto2)

TestCopy(a,1640773176392)
TestCopy(b,1640773176392)
1640773176392
1640773176392

其实是有道理的,因为我是抄案例class。 但是,我想要一种类似于重新创建案例 class 的行为,我只更改了一组静态字段。 上面的示例已经过简化,我本可以重新创建它.问题是针对这样的情况:

  case class TestCopy2(static1: String,
                       static2: String,
                       static3: String,
                       auto: Long = System.currentTimeMillis())

这里只有static1要改,static2static3要复制,还要重新生成auto。 可能吗?

谢谢大家

自定义 apply 方法是可行的,但您也应该能够利用 abstract case class 技巧:

abstract case class TestCopy(static: String, auto: Long = System.currentTimeMillis()) {
  def copy(static: String = static, auto: Long = System.currentTimeMillis()): TestCopy =
    new TestCopy(static, auto)
}

object TestCopy {
  def apply(static: String, auto: Long = System.currentTimeMillis()): TestCopy =
    new TestCopy(static, auto)
}

制作 case class abstract 会抑制自动生成的 applycopy 方法。在这种情况下,自动生成的 apply 基本上就是编译器生成的内容。生成的 copy 通常类似于

def copy(static: String = static, auto: Long = auto): TestCopy

请注意 auto 默认为以前的值,所以这是我们想要更改的行为,因此我们定义了一个自定义 copy 方法来替换编译器生成的方法。

可以通过将构造函数设为私有来消除 auto 的默认值之一;由于 case classes 通常不使用 new 实例化,因此损失不大:

abstract case class TestCopy private (static: String, auto: Long) {
  def copy(static: String = static, auto: Long = System.currentTimeMillis()): TestCopy =
    new TestCopy(static, auto)
}

object TestCopy {
  def apply(static: String, auto: Long = System.currentTimeMillis()): TestCopy =
    new TestCopy(static, auto)
}

现在您可以:

  • 使用默认当前时间创建:TestCopy("foo")
  • 使用预设时间创建:TestCopy("foo", 0)
  • 复制当前时间:TestCopy("foo").copy(static = "bar")
  • 复制预设时间:TestCopy("foo").copy(auto = 0)

不会自动复制瞬态值:

case class Foo(a: Int) { 
   @transient val b: Long = System.currentTimeMillis 
}


val f1 = Foo(1)
Thread.sleep(1000)
val f2 = f1.copy(2)

assert f1.b != f2.b