scala - 在宏中使用私有(private)构造函数

标签 scala macros private-constructor

我想在宏中使用私有(private)构造函数。这个例子是一个正整数,但基本模式不仅可以用于其他数字类型,如偶数,还可以用于字符串派生类型,如电子邮件地址或目录名称。通过将构造函数设为私有(private),用户被拒绝创建非法类型的机会。我有以下代码:

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 构造函数设为私有(private),尽管宏按预期编译,但如果尝试使用宏,则会出现错误。我无法弄清楚如何手动构建表达式树,但我不确定这是否会有所帮助。无论如何我可以做到这一点吗?

即使 PosInt 不是值类,您仍然不能使用私有(private)构造函数。 我会接受不使用值类的答案。 值类的缺点是它们会被类型删除。加上我感兴趣的类,比如 2d 坐标的子集,无论如何都不能作为值类来实现。我实际上对正整数并不感兴趣,我只是将它们用作一个简单的测试平台。我正在使用 Scala 2.11M5。 Scala 2.11 将添加 quasiquotes 功能。我还没有弄清楚如何使用准引号,因为目前它们上的所有 Material 似乎都假定我对 Macro Paradise 很熟悉,而我没有。

最佳答案

不幸的是,对于您要实现的目标,宏不能以这种方式工作。他们只是在编译时操作 AST。无论最终结果是什么,它总是可以用 Scala 字面意思编写的(没有宏)。

因此,为了限制 PosInt 的可能值,您将需要在某个地方进行运行时检查,无论是在公共(public)构造函数中还是在伴随对象的工厂方法中。

如果您不喜欢运行时异常,那么一种可能的方法是:

  • 使构造函数在类上私有(private)。
  • 提供(例如)一个 create返回 Option[PosInt] 的伴随对象上的方法(或 Try[PosInt] ,或您选择的其他类型,允许您在参数超出范围时表达“失败”)。
  • 提供 apply与您的示例类似的伴随对象上的方法,它在编译时验证参数是否在范围内,然后返回一个简单调用 create(x).get 的表达式树.

  • 调用.get在这种情况下,选项上的选项是可以接受的,因为您确定它永远不会是 None .

    缺点是您必须重复检查两次:一次在编译时,一次在运行时。

    关于scala - 在宏中使用私有(private)构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19170137/

    相关文章:

    c++ - C++ 中的 Pimpl 习语和私有(private)构造函数

    Scala cake-pattern 编译错误与 Precog 配置模式

    scala - 合并两个流(有序)以获得最终排序的流

    javascript - scala.js:映射通过 jQuery 加载的 JSON 数组

    macros - 使用宏时每次迭代后参数递增

    c++ - 声明构造函数私有(private)和 =delete 有什么区别?

    scala - 如何让 sbt `console` 使用 -Yrepl-sync?

    C++ 使用 __COUNTER__ 自动生成不同的命名函数

    C 宏 - 通过指针传递与传递给宏时的复制/错误

    Java Final 类或私有(private)构造函数