記錄Scala 2.10宏


Answers

Question

我將從一個例子開始。 下面是在Scala 2.10 List.fill元組作為List.fill的一個等價的List.fill

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返回類型是一種謊言 - 靜態返回類型將包含由參數確定的特定元素和元素類型,如上所示。

那麼我將如何記錄這件事? 在這一點上我並不期待Scaladoc的支持,但我希望有一種習慣或最佳實踐(不僅僅是確保編譯時錯誤消息是清晰的),這會使其運行到宏觀方法中 - 潛在的離奇要求 - 對於Scala 2.10庫的用戶來說不會那麼令人驚訝。

新的宏觀系統(例如, ScalaMockSlickhere列出的其他系統)的最成熟的演示在方法層面上仍然沒有相關文檔。 任何示例或指針都會受到讚賞,包括來自其他語言的具有類似宏觀系統的示例或指針。




Links