允许按名称参数的隐式 class 的宏变体
Macro variant of implicit class that allows for by-name argument
对于DSL,我想介绍一个dup
扩展方法,基本上调用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)
现在我想将参数设为别名值,以便以下内容能够正常工作:
math.random dup 4 // wrong: four times the same value
我正在查看 this question,所以显然没有具有普通值 class 的解决方案,只有:
final class Dup[A](in: () => A) {
def dup(n: Int): Vec[A] = Vector.fill(n)(in())
}
implicit def Dup[A](in: => A): Dup[A] = new Dup(() => in)
math.random dup 4 // ok
...取消值的优点 -class 不涉及装箱。
所以我想知道,是否可以编写一个宏来提供非实例化解决方案,其中参数是按名称命名的?
为什么不呢?
// 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)
}
宏实现:
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
对象的实例化,该对象将代替按名称参数传递,但这是不可避免的。
对于DSL,我想介绍一个dup
扩展方法,基本上调用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)
现在我想将参数设为别名值,以便以下内容能够正常工作:
math.random dup 4 // wrong: four times the same value
我正在查看 this question,所以显然没有具有普通值 class 的解决方案,只有:
final class Dup[A](in: () => A) {
def dup(n: Int): Vec[A] = Vector.fill(n)(in())
}
implicit def Dup[A](in: => A): Dup[A] = new Dup(() => in)
math.random dup 4 // ok
...取消值的优点 -class 不涉及装箱。
所以我想知道,是否可以编写一个宏来提供非实例化解决方案,其中参数是按名称命名的?
为什么不呢?
// 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)
}
宏实现:
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
对象的实例化,该对象将代替按名称参数传递,但这是不可避免的。