为正整数编写宏

时间:2015-04-28 20:07:37

标签: scala scala-macros

考虑以下类型:

sealed trait PosIntCheckResult
case class LteZero(x: Int) extends PosIntCheckResult
case object NotConstant extends PosIntCheckResult

我正在尝试编写一个宏来检查给定的Int是否大于0。

import reflect.macros.Context

def getInt(c: Context)(value: c.Expr[Int]): Either[PosIntCheckResult, Int] = {

    import c.universe._

    value.tree match {
        case Literal(Constant(x)) => if (x > 0) Right(x) else Left(LteZero(x))
        case _                    => Left(NotConstant)
    }
}

Any显示x值:

Test.scala:29: type mismatch;
  found   : Any
  required: Int
    case Literal(Constant(x)) => 
       if (x > 0) Right(x) else Left(LteZero(x))

如何让编译器期望Int而不是Any

1 个答案:

答案 0 :(得分:1)

您必须匹配xInt的模式:

case Literal(Constant(x: Int)) => //When using x here, it is an Int

docs中阅读关于类型的模式匹配和其他类型的模式匹配。

您还应注意,您的宏需要返回Expr才能正常工作。您可以使用reify在每个Exprs构建所需的case。阅读reifydef macros here。我不确定为什么这需要成为一个宏,但如果你只是学习这些技术,这样的东西可能有用:

object Macros {
    def getInt(value: Int): Either[PosIntCheckResult, Int] = macro getIntImpl

    def getIntImpl(c: Context)(value: c.Expr[Int]): c.Expr[Either[PosIntCheckResult,Int]] = {

        import c.universe._

        value.tree match {
            case x@Literal(Constant(const: Int)) if const > 0 => reify(Right(c.Expr[Int](x).splice))
            case x@Literal(Constant(_: Int)) => reify(Left(LteZero(c.Expr[Int](x).splice)))
            case _  => reify(Left(NotConstant))
        }
    }
}