我想在宏中使用私有构造函数。这个例子是一个正整数,但基本模式不仅可以用于其他数字类型,如偶数,还可以用于字符串派生类型,如电子邮件地址或目录名称。通过将构造函数设为私有,用户被拒绝创建非法类型的机会。我有以下代码:
object PosInt
{
import language.experimental.macros
import reflect.runtime.universe._
import reflect.macros.Context
def op(inp: Int): Option[PosInt] = if (inp > 0) Some(new PosInt(inp)) else None
def apply(param: Int): PosInt = macro apply_impl
def apply_impl(c: Context)(param: c.Expr[Int]): c.Expr[PosInt] =
{
import c.universe._
param match {
case Expr(Literal(i)) if (i.value.asInstanceOf[Int] > 0) =>
case Expr(Literal(i)) if (i.value.asInstanceOf[Int] == 0) => c.abort(c.enclosingPosition, "0 is not a positive integer")
case Expr(Literal(i)) => c.abort(c.enclosingPosition, "is not a positive integer")
case _ => c.abort(c.enclosingPosition, "Not a Literal")
}
reify{new PosInt(param.splice)}
}
}
class PosInt (val value: Int) extends AnyVal
但是,如果我将 PosInt 构造函数设为私有,尽管宏按预期编译,但如果尝试使用宏,则会出现错误。我无法弄清楚如何手动构建表达式树,但我不确定这是否会有所帮助。无论如何我可以做到这一点吗?
即使 PosInt 不是值类,您仍然不能使用私有构造函数。我会接受不使用值类的答案。值类的缺点是它们会被类型擦除。加上我感兴趣的类,比如 2d 坐标的子集,无论如何都不能作为值类来实现。我实际上对正整数并不感兴趣,我只是将它们用作一个简单的测试平台。我正在使用 Scala 2.11M5。Scala 2.11 将添加 quasiquotes 功能。我还没有弄清楚如何使用准引号,因为目前它们上的所有材料似乎都假定我对 Macro Paradise 很熟悉,而我没有。