Case Class构造函数参数作为元组提供

时间:2017-02-23 10:07:09

标签: scala tuples shapeless case-class

我的模型看起来像这样:

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中(每个类继承自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)

每个继承的case类使用相同的getHeader(doc)函数来获取标头。 (这就是抽象类A有两个参数的原因)

我希望它看起来更好,以便我可以杀死一些行。

类似的东西:

val b = B(header+xy) 

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

我尝试了无形但是没有用:

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 

当有人知道一些不错的提示或技巧时,我很乐意听到它。

2 个答案:

答案 0 :(得分:1)

您可以为案例类定义另一个apply方法:

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,只需使用新的apply方法构建实例,并直接传递getHeadergetXY的结果。< / p>

答案 1 :(得分:1)

你真的很亲密;你只需要明确说出你想要的类型就是一个元组。以下是所有需要帮助的人的一般例子:

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

但是,如果我可以添加,您的用例可以通过一些额外的建模来简化。然后你根本不需要没有形状。最近我看到很多人滥用案例类。它们旨在作为抽象数据类型(ADT),而不是一般意义上的类。如果你的case类需要包含一些逻辑,那么最好让它只是一个类。

但是,您确实有案例类的用例。为什么不在两个单独的ADT中捕获有关标头和数据点的信息?

这是完整的代码:

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)

当然,如果类A的参数idtime的语义是标题中的参数,您甚至可以A只有一个参数:abstract class A(header: Header)

就个人而言,我认为这是干净,清晰和良好的模型。当然,您的意见可能会有所不同。 :)