如何在 scala 中优雅地聚合 case-class?

how to aggregate case-class in scala gracefully?

case class value(x1:Long, x2: Double, ..., xk: Long, ... ,xn:Int) {

  def add(rValue: Value): Value = {
   Value(
     x1 = x1 + rValue.x1,
     ...
     xk = xk + rValue.xk,
     ...
     xn = xn + rvalu.xn
   )
 }

}

我想聚合case-class('value'),我觉得这个手工实现在n很大的时候(比如n=500?)不优雅

案例 类 的字段是 immutable,return 一个包含所有更新字段的新实例。

case class Value(x: Int, y: Int) { 
  def + (other: Value): Value =
    Value(x + other.x, y + other.y)
}

Value(10, 20) + Value(10, 20)
//res0: Value = Value(20,40)

Value(10, 20) + Value(20, 30) + Value(30, 50)
//res1: Value = Value(60,100)

这是一个在 Scala3 中仅适用于 build-in api 的解决方案:

trait Add[N] { def add(x: N, y: N): N }

object Add:
  import scala.deriving.Mirror.ProductOf
  
  given Add[Int]        = _ + _
  given Add[Long]       = _ + _
  given Add[Float]      = _ + _
  given Add[Double]     = _ + _
  given Add[EmptyTuple] = (_, _) => EmptyTuple
  given [H, T <: Tuple](using ha: Add[H], ta: Add[T]): Add[H *: T] = 
    case (hx*:tx, hy*:ty) => ha.add(hx, hy) *: ta.add(tx, ty)
  given [P <: Product](using p: ProductOf[P], a: Add[p.MirroredElemTypes]): Add[P] = 
    (x, y) => p.fromProduct(a.add(Tuple.fromProductTyped(x), Tuple.fromProductTyped(y)))
  

那么我们可以定义Valueclass为:

scala> case class Value(x1: Int, x2: Float, x3: Double):
     |   def add(that: Value): Value = summon[Add[Value]].add(this, that)
     |

scala> Value(1, 2, 3).add(Value(3, 4, 5))
val res0: Value = Value(4,6.0,8.0)