作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想编写一个返回类型取决于参数的宏。简化示例:
def fun[T](methodName: String) = macro funImpl[T]
def funImpl[T: WeakTypeTag](c: Context)(methodName: c.Expr[String]): /* c.Expr[T => return type of T.methodName] */ = {
// return x => x.methodName
}
显然 funImpl
被注释掉的返回类型是非法的。我试过简单地返回一个 Tree
,但这会产生错误:
[error] macro implementation has wrong shape:
[error] required: (c: scala.reflect.macros.Context): c.Expr[Any]
[error] found : (context: scala.reflect.macros.Context): context.Tree
[error] type mismatch for return type: c.universe.Tree does not conform to c.Expr[Any]
[error] def fun[T] = macro PrivateMethodMacro.funImpl[T]
[error] ^
可以写这样的宏吗?显然,如果返回类型作为另一个类型参数传递,就像对 Is it possible to write a scala macro whose returntype depends on argument? 的回答一样,这是可能的。但这不是我想要的。
最佳答案
是的,这是可能的,感谢 whitebox macros 的魔力: 你可以告诉编译器返回类型是 c.Expr[Any]
并且它会推断出更精确的类型。
此行为 shocked me when I first ran into it ——它非常非常强大,非常非常可怕——但它肯定是有意的,并且将继续得到支持,尽管 2.11 将区分白盒和黑盒宏,而前者可能会更长时间地处于实验状态(如果他们永远不会离开它)。
例如,以下是您所要求的内容的速写(我在此处使用 quasiquotes 通过 macro paradise plugin 表示 2.10,但如果没有准引号,它只会更冗长):
import scala.language.experimental.macros
import scala.reflect.macros.Context
def funImpl[T: c.WeakTypeTag](c: Context)(
method: c.Expr[String]
): c.Expr[Any] = {
import c.universe._
val T = weakTypeOf[T]
val methodName: TermName = method.tree match {
case Literal(Constant(s: String)) => newTermName(s)
case _ => c.abort(c.enclosingPosition, "Must provide a string literal.")
}
c.Expr(q"(t: $T) => t.$methodName")
}
def fun[T](method: String) = macro funImpl[T]
然后:
scala> fun[String]("length")
res0: String => Int = <function1>
您可以看到推断的类型正是您想要的,而不是 Any
。您可以(并且可能应该)将 funImpl
的返回类型设置为 c.Expr[T => Any]
并返回类似 c.Expr[T = > Any](q"_.$methodName")
,但这本质上只是文档——它对在这种情况下如何推断宏的返回类型没有任何影响。
关于scala - 宏返回类型取决于参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21980747/
我是一名优秀的程序员,十分优秀!