在Scala宏中处理名称参数 [英] Handling by-name parameters in Scala macro

查看:127
本文介绍了在Scala宏中处理名称参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个宏,可以对嵌套函数应用程序进行一些分析.它匹配应用程序并以这种方式检索参数类型:

I have a macro that does some analysis on nested function applications. It matches applications and retrieve the parameter types this way:

case q"$f[..$targs](..$args)(...$otherArgs)" =>

    // retrieve the list of all parameter types
    val paramTpes = f.tpe match {
      case pmt: PolyType if pmt.paramLists.size == 0 =>
        Seq()
      case pmt: PolyType =>
        pmt.paramLists(0) map {_.typeSignature
             .substituteTypes(pmt.typeParams, targs map (_.tpe))}
      case pmt: MethodType if pmt.paramLists.size == 0 =>
        Seq()
      case pmt: MethodType =>
        pmt.paramLists(0) map (_.typeSignature)
    }

现在,如果碰巧有按名称命名的参数,我得到的是某种奇怪的类型,可以打印=> T,但无法与任何内容匹配.反射API中似乎没有任何工具可以正确处理这些问题. 我想做的是在T的情况下检索T,因为=> T会在生成的代码中引起进一步的问题.

Now, if there happen to be by-name parameters, what I get is some weird type that prints => T but cannot be matched with anything. There seem to be no facility in the reflection API to handle these properly. What I would like to do is retrieve T in case it' a => T, because => T causes further problems in the generated code.

推荐答案

通常,使用提取器.有时我必须查看运行时类是什么,以记住要使用的提取器.我不是每天都使用API​​.

Usually, use the extractors. Sometimes I have to see what the runtime class is, to remember what extractor to use. I don't use the API every day.

scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._

scala> class X { def x(i: => Int) = i * 2 }
defined class X

scala> typeOf[X].member(TermName("x"))
res0: reflect.runtime.universe.Symbol = method x

scala> .typeSignature
res1: reflect.runtime.universe.Type = (i: => scala.Int)scala.Int

scala> res1 match { case MethodType(ps, res) => ps }
res2: List[reflect.runtime.universe.Symbol] = List(value i)

scala> .head
res3: reflect.runtime.universe.Symbol = value i

scala> .typeSignature
res4: reflect.runtime.universe.Type = => scala.Int

scala> res4.getClass
res5: Class[_ <: reflect.runtime.universe.Type] = class scala.reflect.internal.Types$ClassArgsTypeRef

scala> res4 match { case TypeRef(pre, sym, args) => sym }
res6: reflect.runtime.universe.Symbol = class <byname>

scala> res4 match { case TypeRef(pre, sym, args) => args }
res7: List[reflect.runtime.universe.Type] = List(scala.Int)

scala> definitions
res8: reflect.runtime.universe.DefinitionsApi = scala.reflect.internal.Definitions$definitions$@4e80a001

scala> definitions.By
ByNameParamClass   ByteClass   ByteTpe

scala> definitions.ByNameParamClass
res9: reflect.runtime.universe.ClassSymbol = class <byname>

我隐约记得这个特殊名称,但是我得到一个用于模式匹配的稳定前缀吗?我想不是.

I vaguely remember the special name, but do I get a stable prefix for pattern matching? I guess not.

scala> res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args }
<console>:20: error: stable identifier required, but scala.reflect.runtime.`package`.universe.definitions.ByNameParamClass found.
 Note that method ByNameParamClass is not stable because its type, => reflect.runtime.universe.ClassSymbol, is volatile.
              res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args }
                                                         ^

scala> val k = definitions.ByNameParamClass
k: reflect.runtime.universe.ClassSymbol = class <byname>

scala> res4 match { case TypeRef(pre, k, args) => args }
res11: List[reflect.runtime.universe.Type] = List(scala.Int)

scala> 

这篇关于在Scala宏中处理名称参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆