获取案例类中相同类型的字段值的列表

时间:2019-01-24 16:14:08

标签: scala

我有一个类似的类,它给出了如果有人感兴趣的情况下重叠算法的哪一部分出错的详细答案,我希望将来在数据中存在许多其他可能的无效性来增强它。

case class Validity(grouping: Boolean = true,
                    matchingValuesValidation: Boolean = true) {
  def compute: Boolean =
    List(grouping,
         matchingValuesValidation
    ).forall(identity)

  def merge(ot: Validity): Validity =
    Validity(
      grouping && ot.grouping,
      matchingValuesValidation && ot.matchingValuesValidation
    )
}

我知道所有字段都是布尔值,计算不会改变。我想让方法计算并合并以某种方式遍历所有字段,因此,如果我对其进行增强,则无需重复执行3次。如果使用Map,则可以添加所需的任意键->值对,这是不希望的,我想保留结构。同时,我想通过简单地向该类添加另一个布尔参数来增强该类。任何想法都非常感谢,在此先谢谢

2 个答案:

答案 0 :(得分:1)

你知道吗? YOLO。

case class Validity(grouping: Boolean = true, matchingValuesValidation: Boolean = true) {

  def values: List[Boolean] = {
    import scala.reflect.runtime.universe._
    val fields = typeOf[Validity].members.collect { case m: MethodSymbol if m.isCaseAccessor => m }.toList
    val mirror = runtimeMirror(this.getClass.getClassLoader)
    fields.map(mirror.reflect(this).reflectField(_).get.asInstanceOf[Boolean])
  }

  def compute: Boolean = values.forall(identity)
  def merge(ot: Validity) = Validity.fromValues(this.values.zip(ot.values).map(v => v._1 && v._2).reverse)
}

object Validity {
  def fromValues(values: List[Boolean]): Validity = {
    import scala.reflect.runtime.universe._
    val mirror = runtimeMirror(Validity.getClass.getClassLoader)
    val constructorSymbol = typeOf[Validity].decl(termNames.CONSTRUCTOR).asMethod
    val classSymbol = mirror.reflectClass(typeOf[Validity].typeSymbol.asClass)
    val constructor = classSymbol.reflectConstructor(constructorSymbol)
    constructor(values:_*).asInstanceOf[Validity]
  }
}

答案 1 :(得分:1)

您可以使用无形来代替繁重的工作:

import shapeless.ops.hlist.{Mapper, Zip}
import shapeless.{::, Generic, HList, HNil, Poly1}

private sealed trait lowPrioMergerMapper extends Poly1 {
  implicit def mapperT[T]: Case.Aux[(T, T), T] = at[(T, T)] { case (v1, _) => v1}
}
private object MergerMapper extends lowPrioMergerMapper {

  implicit def mapperBoolean: Case.Aux[(Boolean, Boolean), Boolean] = at[(Boolean, Boolean)] { case (v1, v2) => v1 && v2 }
}

def booleanFieldMerger[T, HL <: HList, ZOut <: HList](a: T, b: T)(
  implicit
  gen: Generic.Aux[T, HL],
  zipWith: Zip.Aux[HL :: HL :: HNil, ZOut],
  mapper: Mapper.Aux[MergerMapper.type ,ZOut, HL]
): T = {
  val aRepr = gen.to(a)
  val bRepr = gen.to(b)
  gen.from((aRepr zip bRepr) map MergerMapper)
}

用法如下:

val validity = Validity()
val validity2 = Validity(a = false)
val validity3 = Validity(b = false)
val validity4 = Validity(a = false, b = false)

booleanFieldMerger(validity,validity2) shouldBe validity2
booleanFieldMerger(validity2,validity3) shouldBe validity4
List(validity2,validity3).fold(validity)((a,b) => booleanFieldMerger(a,b)) shouldBe validity4

对于字段的评估,您可以使用:

import shapeless.HList
import shapeless.ops.hlist._

def evaluateBooleanFields[T, HL <: HList](input: T)(
  implicit
  gen: Generic.Aux[T, HL],
  toTrav: ToList[HL,Any]): Boolean = {
  gen.to(input).toList.foldLeft(true){
    case (acc, e: Boolean) => acc && e
    case (acc, _) => acc}
}

用法与上面相同:

evaluateBooleanFields(validity) shouldBe true
evaluateBooleanFields(validity2) shouldBe false