简体   繁体   English

如何在Scala的编译时检查某些T是否为case类?

[英]How to check if some T is a case class at compile time in Scala?

I have the following macro: 我有以下宏:

package macros

import scala.reflect.macros.blackbox.Context

object CompileTimeAssertions {
  def mustBeCaseClass[T]: Unit =
    macro CompileTimeAssertionsImpl.mustBeCaseClass[T]
}

object CompileTimeAssertionsImpl {
  def mustBeCaseClass[T: c.WeakTypeTag](c: Context): c.Expr[Unit] = {
    import c.universe._
    val symbol = c.weakTypeTag[T].tpe.typeSymbol
    if (!symbol.isClass || !symbol.asClass.isCaseClass) {
      c.error(c.enclosingPosition, s"${symbol.fullName} must be a case class")
    }
    reify(Unit)
  }
}

It works when generics aren't involved, but fails when they are: 它在没有涉及泛型时起作用,但在它们出现时失败:

import macros.CompileTimeAssertions._
import org.scalatest.{Matchers, WordSpec}

case class ACaseClass(foo: String, bar: String)

class NotACaseClass(baz: String)

class MacroSpec extends WordSpec with Matchers {
  "the mustBeCaseClass macro" should {
    "compile when passed a case class" in {
      mustBeCaseClass[ACaseClass]
    }

    "not compile when passed a vanilla class" in {
//      mustBeCaseClass[NotACaseClass] // fails to compile as expected.
    }

    "compile when working with generics" in {
//      class CaseClassContainer[T] { mustBeCaseClass[T] } // fails to compile.
//      new CaseClassContainer[ACaseClass]
    }
  }
}

The compiler error is mine: 编译器错误是我的:

MacroSpec.CaseClassContainer.T must be a case class

I'd like to find out what T is when the CaseClassContainer is instantiated. 我想知道实例化CaseClassContainer时的T是什么。 Is that even possible? 这甚至可能吗? If it is can you provide an example? 如果是,你可以提供一个例子吗?

Thanks in advance. 提前致谢。

Thanks to Eugene and Travis' advice I was able to solve this problem with type classes. 感谢Eugene和Travis的建议,我能够用类型类来解决这个问题。 Here's the solution: 这是解决方案:

package macros

import scala.reflect.macros.blackbox.Context

trait IsCaseClass[T]

object IsCaseClass {
  implicit def isCaseClass[T]: IsCaseClass[T] =
    macro IsCaseClassImpl.isCaseClass[T]
}

object IsCaseClassImpl {
  def isCaseClass[T]
      (c: Context)
      (implicit T: c.WeakTypeTag[T]): c.Expr[IsCaseClass[T]] = {
    import c.universe._
    val symbol = c.weakTypeTag[T].tpe.typeSymbol
    if (!symbol.isClass || !symbol.asClass.isCaseClass) {
      c.abort(c.enclosingPosition, s"${symbol.fullName} must be a case class")
    } else {
      c.Expr[IsCaseClass[T]](q"_root_.macros.IsCaseClassImpl[$T]()")
    }
  }
}

case class IsCaseClassImpl[T]() extends IsCaseClass[T]

And here is the usage: 以下是用法:

import macros.IsCaseClass
import org.scalatest.{Matchers, WordSpec}

case class ACaseClass(foo: String, bar: String)

class NotACaseClass(baz: String)

class CaseClassContainer[T: IsCaseClass]

class MacroSpec extends WordSpec with Matchers {
  "the code" should {
    "compile" in {
      new CaseClassContainer[ACaseClass]
    }

    "not compile" in {
//      new CaseClassContainer[NotACaseClass]
    }
  }
}

Worth noting the use of abort instead of error . 值得注意的是使用abort而不是error Abort returns Nothing whereas error returns Unit . 中止返回Nothing而错误返回Unit The latter was fine when the macro wasn't returning anything. 当宏没有返回任何东西时后者很好。

In scala 2.11 and above, it's much simplier now. 在scala 2.11及更高版本中,它现在更简单了。 I've created a small project that does it : https://github.com/samupra/CaseClassChecker 我已经创建了一个小项目: https//github.com/samupra/Cas​​eClassChecker

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在编译时验证 Scala 案例 class - Validate Scala case class at compile time [Scala工具箱]:在运行时编译一个Case Class,然后实例化它 - [Scala Toolbox]: Compile a Case Class at run-time and then instantiate it Scala:检查案例类树是否不包含任何null - Scala: check that a case class tree doesn't contain any null Scala 白框宏如何检查 class 字段是否属于案例类型 class - Scala whitebox macro how to check if class fields are of type of a case class 如何在编译时检查String中的SQL,语言语法(Scala) - How to check SQL, Language syntax in String at compile time (Scala) 在Scala中,如何对伴随对象执行编译时类型检查? - In Scala, How to perform compile-time type check on companion object? 编译一些属性的时间检查 - Compile time check on some property 如何使用scala将RDD [某些情况下的类]转换为csv文件? - How to convert RDD[some case class] to csv file using scala? 如何自动将修改应用于 Scala 中案例类的所有/某些字段? - How to automaticaly apply modifications to all/some fields of a case class in scala? Scala编译时间检查构造函数调用的位置 - Scala compile time check for location of constructor calls
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM