首先是一些代码来说明我的问题
trait Condition extends Serializable {
def column: String
def value(row: Row): String = row.getAs[String](column)
def isTrue(row: Row): Boolean
}
Trait Condition允许定义应用于Row类的任意条件(Spark Row类,以防任何人想知道)。这个特征可以由具体的条件类继承,以模拟一个想要针对特定行检查的不同条件,例如:
case class List(values: String*)(val column: String) extends Condition {
override def isTrue(row: Row): Boolean = values.contains(value(row))
}
case class IsInteger()(val column: String) extends Converter(Long.parseLong)
val condition = List("1", "A")("code")
val isCodeValid = condition.isTrue(row) // assuming the row has a column called "code"
现在我希望能够通过复合条件类组合多个条件:
case class And(conditions: Condition*)(val column: String) extends Condition {
override def isTrue(row: Row): Boolean = conditions.forall(_.isTrue(row))
}
这允许我写出这样的条件:
val condition = And(List("1", "A")("id"), IsInteger()("id"))("id")
但是,,这会为每个条件重复列名称。
我更喜欢的是And(List("1", "A"), IsInteger())("id")
,其中And
条件会将其列名应用于所有基本条件 - 但是,我正在努力学习语法。
基本上,我必须为And
定义一个重载的构造函数,而不是采用vararg Condition*
参数,而是采用部分应用的Condition
vararg班;类似于
def this(partials: String => Condition*) = this(partials(column): _*)
这个特殊的语法无法编译,我不确定应该是什么样的语法,或者甚至是可能的。
编辑:根据多个建议,重载的构造函数看起来像
def this(partials: (String => Condition)*)(column: String) =
this(partials.map(_(column)):_*)(column)
然而,这给了我一个错误
Error:(9, 6) double definition:
constructor And: (conditions: Condition*)(column: String)And at line 8
and constructor And: (partials: String => Condition*)(column: String)And at line 9
have same type after erasure: (conditions: Seq, column: String)And
def this(partials: (String => Condition)*)(column: String) =
this(partials.map(_(column)):_*)(column)
我还尝试了相同的重载构造函数而没有列curry,但是后来它抱怨缺少列参数(不出意外,事后看来):
def this(partials: (String => Condition)*) = this(partials.map(_(column)):_*)
Error:(9, 67) not found: value column
def this(partials: (String => Condition)*) = this(partials.map(_(column)):_*)
答案 0 :(得分:1)
立即想到的是,并非每个Condition
都在一列上。例如。考虑"所有列都相同"或不同列上的两个条件And
。所以我们可以稍微改变设计:
trait Condition extends Serializable {
def isTrue(row: Row): Boolean
}
trait SingleColumnCondition extends Serializable {
def value(row: Row, column: String): String = row.getAs[String](column)
def apply(column: String): Condition
}
然后:
case class List(values: String*) extends SingleColumnCondition {
// requires Scala 2.12 to define a Condition by a lambda
override def apply(column: String) = row => values.contains(value(row, column))
}
case class And(conditions: Condition*) extends Condition {
override def isTrue(row: Row): Boolean = conditions.forall(_.isTrue(row))
}
case class SingleColumnAnd(conditions: SingleColumnCondition*) extends SingleColumnCondition {
override def apply(column: String) = And(conditions.map(_(column))
}
您也可以使用DummyImplicit
重载And.apply
(当然也可以使用当前方法中的构造函数):
object And {
def apply(conditions: SingleColumnCondition*)(implicit d: DummyImplicit): SingleColumnCondition =
SingleColumnAnd(conditions: _*)
}