Scala参考' tupled'一般来自案例类

时间:2014-10-01 19:13:14

标签: scala

我正在尝试编写一个样板函数,该函数可以接受一对通用案例类对象,并在其val集合上执行一些操作,然后返回案例类的新实例。

在更详细的层面上,这不是本问题的预期焦点,我正在执行的操作是压缩两个两个val列表,并通过List选择性地决定将哪个元组项放入新实例中[Boolean]表示左对象或右对象的标志。

我已经编写了大部分概念,并且到目前为止我的研究工作最好的策略是将case类对象转换为vals列表(使用Product.productIterator)然后最终转换为将val转换为元组(SO reference)以提供给Function.tupled(SO reference)(在案例类中可用)。

trait PermissionMask[B <: Product] {
    val permissionMask: List[Boolean]

    def mergePermissibleEdits(userObject: B, trustedObject: B) = {
      val possibleValues = (userObject.productIterator.toList) zip (trustedObject.productIterator.toList)
      val valuesWithFlags = possibleValues zip permissionMask

      val mergedObjectList = valuesWithFlags map { case ((userValue, trustedValue), userEditable) => if (userEditable) userValue else trustedValue }

      //TODO: Not possible, I don't have a direct reference to the case class since it's generic, not sure how to get the reference
      B.tupled(mergedObjectList) //I have implicit conversions to tuple1-22 from list
    }
  }

如果我没有使用泛型并且知道具体的case类,我可以简单地调用SomeCaseClass.tupled(mergedObjectList)。然而,由于它是通用的,我对如何(如果可能的话)我可以进行相同的调用模糊不清。

1 个答案:

答案 0 :(得分:2)

如上所述,您无法使用tupled,因为它不适用于所有案例类apply方法。这是一个相当hacky的版本,但可行的&#39;可以&#39;工作。这将获取第一个构造函数并将合并的参数列表应用于它。 警告,这非常可疑且非常容易破碎,我不会在生产中使用它

  def mergePermissibleEdits[B <: Product : ClassTag](userObject: B, trustedObject: B, permissionMask: List[Boolean]) = {
    val possibleValues = userObject.productIterator.toList.map(_.asInstanceOf[AnyRef]) zip trustedObject.productIterator.toList.map(_.asInstanceOf[AnyRef])
    val valuesWithFlags = possibleValues zip permissionMask

    val mergedObjectList = valuesWithFlags map { case ((userValue, trustedValue), userEditable) => if (userEditable) userValue else trustedValue}

    implicitly[ClassTag[B]].runtimeClass.getConstructors.head.newInstance(mergedObjectList: _*).asInstanceOf[B]
  }

  case class Id(id1: Int, id2: String, id3: Double)

  println(mergePermissibleEdits(Id(1, "test", 3.0), Id(4, "works", 6.0), List(true, false, true)))
  //prints Id(1,works,3.0)