在编译时验证 Scala 案例类

Posted

技术标签:

【中文标题】在编译时验证 Scala 案例类【英文标题】:Validate Scala case class at compile time 【发布时间】:2019-11-10 15:53:42 【问题描述】:

我在 Scala 2.11 应用程序中有一个案例类,它有一个依赖于案例类字段名称的方法,如下所示:

final case class Foo(
  val a: String,
  val b: String,
  val c: String
) 
  def partitionColumns: Seq[String] = Seq("b", "c")

如果 partitionColumns 之一不作为案例类上的字段存在,我希望编译时检查抛出错误,例如会捕获此问题的内容:

final case class Bar(
  val a: String,
  val b: String,
  val c: String
) 
  def partitionColumns: Seq[String] = Seq("x", "y")


到目前为止,我已经将分区行为封装在一个特征中,这减少了可能出错的次数/位置:

sealed trait partitionedByBAndC 
  def b: String
  def c: String
  def partitionColumns: Seq[String] = Seq("b", "c")


final case class Foo(
  val a: String,
  val b: String,
  val c: String
) extends PartitionedByBAndC

但是如果特征写错了,就没有检查,例如这段代码,编译得很好:

sealed trait partitionedByBAndCIncorrect 
  def b: String
  def c: String
  def partitionColumns: Seq[String] = Seq("x", "y")


final case class Foo(
  val a: String,
  val b: String,
  val c: String
) extends partitionedByBAndCIncorrect

在 Scala 2.13 中,我可能可以使用 productElementNames,但我使用的是 Scala 2.11(和 Spark 2.3)。如果不从类/特征中实际构造一个对象,我不确定该怎么做,这似乎是很多开销(考虑到代码中有许多这些特征)。

【问题讨论】:

为什么会有这些字段? 用于将数据写入分区的配置单元表。 好的,你试过使用反射吗? 我没有,我不太熟悉。我去看看。 【参考方案1】:

有一个小型库(scala-nameOf) 可用于执行此操作:

final case class Foo(
                    val a: String,
                    val b: String,
                    val c: String
                  ) 
import com.github.dwickern.macros.NameOf._
def partitionColumns: Seq[String] = Seq(nameOf(this.a),nameOf(this.b))

这不会为不属于案例类的字段编译

【讨论】:

谢谢,效果很好。在 Scala 2.13 中还有 productElementNames 也可以。

以上是关于在编译时验证 Scala 案例类的主要内容,如果未能解决你的问题,请参考以下文章

“模块化”Scala 指南

在模拟类scala中初始化变量

我可以从 Avro 模式定义中获取 Scala 案例类定义吗?

Scala在匹配多个案例类时提取参数以进行理解

20.scala的内部类

Gradle + Scala Plugin + Zinc 1.3.5 将 Protobuf 3.7 泄漏到编译器类路径