Case Class 构造函数参数以元组形式给出

Case Class constructor parameter give as tuple

我的模型看起来像这样:

abstract class A(id:String, val time:Int) extends Ordered[A]{
    override def compare(that:TrackingEvent) = this.time.compare(that.time)
}

case class B(id:String, override val time: Int, x:Int, y:int) extends A(id,time) {
    //some methods
}
// more Case Classes who inherit from A

我从 mongodb 中获取一些数据并将它们存储在某些 case-classes 中(每个 class 都继承自 A)

我现在做的是:

val header = getHeader(doc) //doc => actual row, return: Tuple2(String,Int)
val xy = getXYDatapoint(doc) // return: Tuple2(Int,Int)
val b = B(header._1,header._2,xy._1,xy._2)

每个继承案例 class 使用相同的 getHeader(doc) 函数来获取 header。 (这就是摘要 class A 有两个参数的原因)

我希望它看起来更好,这样我就可以删除一些台词。

类似于:

val b = B(header+xy) 

或者别的什么。我可以更改整个 Scala 代码,并愿意寻求任何帮助,让它看起来更好(我是 Scala 的新手)

我试过 shapeless 但没用:

import shapeless._
import syntax.std.tuple._

val header = getHeader(doc)
val xy = getXY(doc)
val param = header++xy

val b = (B.apply _).tupled(param) // didn't work because param is of type prepend.Out
val b = (B.apply _).tupled(("a",2,3,4)) // would work 

如果有人知道一些不错的提示或技巧,我会很高兴听到。

您可以为案例定义另一个应用方法 class:

case class B(id: String, override val time: Int, x: Int, y: Int) extends A(id, time)
object B {
  def apply(header: (String, Int), coordinates: (Int, Int)): B =
    B(header._1, header._2, coordinates._1, coordinates._2)
}

现在您可以将其用作:

val header = getHeader(doc)
val coords = getXY(doc)
val b = B(header, coords)

这很好,因为您不再需要调用 tupled,您只需使用新的应用方法构建实例并直接传递 getHeadergetXY 的结果.

你们真的很亲密;您只需要明确说明您的预期类型是一个元组。以下是所有有需要的人的一般示例:

import shapeless.syntax.std.tuple._

case class Test(a: Int, b: Int, c: String, d: Int)

val tuple: (Int, Int, String, Int) = (1, 2) ++ ("a", 3)

Test.tupled(tuple) // works

但是,如果我可以补充一点,您的用例可以通过一些额外的建模来简化。那么你根本不需要无形的。最近我看到很多人滥用 classes 大小写。它们旨在作为抽象数据类型 (ADT),而不是一般意义上的 classes。如果您的案例 class 需要包含一些逻辑,那么最好将其设为 class.

不过,您确实有案例 classes 的用例。为什么不在两个单独的 ADT 中捕获有关 header 和数据点的信息?

完整代码如下:

case class Header(id: String, time: Int)
case class DataPoint(x: Int, y: Int)

abstract class A(id: String, val time: Int) {
  // whatever
}

class B(header: Header, dataPoint: DataPoint) extends A(header.id, header.time) {
  // whatever
}

val dataPoint = DataPoint(1, 2)
val header = Header("header", 42)

val b = new B(header, dataPoint)

当然,如果 class A 的参数 idtime 的语义是来自 header 的语义,你甚至可以使 A 只接受一个参数:abstract class A(header: Header).

就我个人而言,我认为这是干净、清晰和 well-modelled。当然,你的看法可能不同。 :)