我将从一个例子开始。下面是List.fill
元组等效为斯卡拉2.10宏:记录Scala 2.10宏
import scala.language.experimental.macros
import scala.reflect.macros.Context
object TupleExample {
def fill[A](arity: Int)(a: A): Product = macro fill_impl[A]
def fill_impl[A](c: Context)(arity: c.Expr[Int])(a: c.Expr[A]) = {
import c.universe._
arity.tree match {
case Literal(Constant(n: Int)) if n < 23 => c.Expr(
Apply(
Select(Ident("Tuple" + n.toString), "apply"),
List.fill(n)(a.tree)
)
)
case _ => c.abort(
c.enclosingPosition,
"Desired arity must be a compile-time constant less than 23!"
)
}
}
}
我们可以按如下方式使用此方法:
scala> TupleExample.fill(3)("hello")
res0: (String, String, String) = (hello,hello,hello)
这家伙是几个方面的一个奇怪的鸟。首先,arity
参数必须是一个字面整数,因为我们需要在编译时使用它。在以前的Scala版本中,对于一个方法来说,没有办法(据我所知)甚至不知道它的一个参数是否是编译时的文字。
二,Product
返回类型is a lie - 静态返回类型将包含由参数确定的特定元素和元素类型,如上所示。
那么我会如何记录这件事?在这一点上我并不期待Scaladoc的支持,但我希望有一种习惯或最佳实践(不仅仅是确保编译时错误消息是清晰的),这会使其运行到宏观方法中 - 潜在的离奇要求 - 对于Scala 2.10库的用户来说不会那么令人惊讶。
新的宏系统(例如,ScalaMock,Slick,其他列出的here)的最成熟的演示在方法级别上仍然是相对未记录的。任何示例或指针都会受到赞赏,包括来自其他语言的具有类似宏观系统的示例或指针。
关于ScalaMock,作为作者,我非常感谢关于如何改进文档的建议。 ScalaMock实际上是一个DSL,因此记录单个方法并不一定意味着太多。我试图在这里整体记录DSL:http://scalamock.org/api/index.html#org.scalamock.package,这里有入门文档:http://www.paulbutcher.com/2012/10/scalamock3-step-by-step /我可以添加哪些帮助? –
@PaulButcher:我不是故意批评ScalaMock,而是编辑了更清晰的答案。我发现读取代码非常有用,因为我一直在试图理解Scala的宏,我认为高级文档非常清晰。 –
没有冒犯。但是,我肯定会感谢任何和所有我可以改进的方法。 –