Как сопоставить методы, которые возвращают Future и имеют несколько аргументов или список с несколькими аргументами (карри)?

Я играю со скаламетой и хочу иметь общую аннотацию измерения, которая отправляет измерения о том, сколько времени заняло выполнение метода.

Я использовал демонстрацию аннотации кеша Цин Вэя. https://www.cakesolutions.net/teamblogs/scalameta-tut-cache

Это работает для не асинхронных методов, но мой атрибут не совпадает с методами, которые возвращают Future из-за списка аргументов ExecutionContext.

Моя аннотация выглядит так:

package measurements 

import scala.concurrent.Future
import scala.meta._

class measure(name: String) extends scala.annotation.StaticAnnotation {
  inline def apply(defn: Any): Any = meta {
    defn match {
      case defn: Defn.Def => {
        this match {
          case q"new $_($backendParam)" =>
            val body: Term = MeasureMacroImpl.expand(backendParam, defn)
            defn.copy(body = body)
          case x =>
            abort(s"Unrecognized pattern $x")
        }
      }
      case _ =>
        abort("This annotation only works on `def`")
    }
  }
}

object MeasureMacroImpl {

  def expand(nameExpr: Term.Arg, annotatedDef: Defn.Def): Term = {
    val name: Term.Name = Term.Name(nameExpr.syntax)
    annotatedDef match {
      case q"..$_ def $methodName[..$tps](..$nonCurriedParams): $rtType = $expr" => {
        rtType match {
          case f: Future[Any] => q"""
            val name = $name
            println("before " + name)
            val future: ${rtType} = ${expr}
            future.map(result => {
              println("after " + name)
              result
            })
           """
          case _ => q"""
            val name = $name
            println("before " + name)
            val result: ${rtType} = ${expr}
            println("after " + name)
            result
           """
        }
      }
      case _ => abort("This annotation only works on `def`")
    }
  }
}

Я использую аннотацию как это:

@measure("A")
def test(x: String): String = x

@measure("B")
def testMultipleArg(x: Int, y: Int): Int = x + y

Я хотел бы использовать его с такими асинхронными методами:

@measure("C")
def testAsync(x: String)(implicit ec: ExecutionContext) : Future[String] = {
 Future(test(x))
}

но я получаю следующую ошибку:

exception during macro expansion: 
scala.meta.internal.inline.AbortException: This annotation only works on `def`

Я предполагаю, что проблема заключается в сопоставлении MeasureMacroImpl, но я не уверен, как сопоставить несколько групп аргументов. Не могли бы вы, ребята, помочь мне? Любые идеи или примеры кода будут с благодарностью. Я довольно новичок в scala и scala meta, поэтому извиняюсь, если задал тривиальный вопрос.

1 ответ

Решение

Вы получаете ошибку, потому что MeasureMacroImpl не соответствует параметрам карри.

Это довольно тривиально, чтобы соответствовать карри параметры, просто используйте

scala case q"..$_ def $methodName[..$tps](...$nonCurriedParams): $rtType = $expr"

Обратите внимание на ...$nonCurriedParams вместо ..$nonCurriedParams

Другие вопросы по тегам