对于DSL,我想介绍一种基本上调用dup
的{{1}}扩展方法,例如
Vector.fill
现在我想让参数成为一个名字值,以便以下内容正常工作:
import scala.collection.immutable.{IndexedSeq => Vec}
implicit final class Dup[A](private val in: A) extends AnyVal {
def dup(n: Int): Vec[A] = Vector.fill(n)(in)
}
3 dup 4 // Vector(3, 3, 3, 3)
我正在查看this question,所以显然没有纯值类的解决方案,只有:
math.random dup 4 // wrong: four times the same value
...撤消没有拳击的价值类的优势。
所以我想知道,是否有可能编写一个提供无实例化解决方案的宏,其中参数是按名称?
答案 0 :(得分:1)
为什么不呢?
// Doesn't matter if it's value class or not, code generated by macro
// will contain no references to it.
implicit final class Dup[A](in: A) {
def dup(n: Int): Vec[A] = macro Macros.dupImpl[A]
}
object Dup {
def dup[A](in: => A, n: Int) = Vector.fill(n)(in)
}
宏impl:
import scala.reflect.macros.blackbox
object Macros {
def dupImpl[A](c: blackbox.Context)(n: c.Expr[Int]): c.Tree = {
import c.universe._
val q"$conv($in)" = c.prefix.tree
q"Dup.dup($in, $n)"
}
}
可以假设c.prefix
包含隐式转换中包含的in
参数的树(如果不是,我们可以添加一些验证代码并发出编译错误)。我们只需打开它并获取代表in
的原始树。然后我们直接将它传递给Dup.dup
,完全丢弃最终生成的代码中的隐式转换。
唯一的即时消息将是Function0
对象的实例化,它将被传递来代替按名称参数,但这是不可避免的。