首页 > 解决方案 > 找到 Scala 3 宏:(x$1 : x$1².reflect.Symbol) 必需:quoted.Quotes

问题描述

def printParamsImpl[A](using Quotes, Type[A]): Expr[() => Unit] = {
  import quotes.reflect._
    TypeRepr.of[A].typeSymbol.declaredMethods.collect {
      case m if m.paramSymss.size == 1 =>
        val params = m.paramSymss.head
        val paramNames = {
          val exprList = params.map {  p =>
            Expr(p.name)
          }
          Expr.ofList(exprList)
        }
    
        '{ 
          println(${paramNames})
        }
    }

上面的代码抱怨

Found:    (x$1 : x$1².reflect.Symbol)
Required: quoted.Quotes

where:    x$1  is a parameter in an anonymous function in method printParamsImpl
          x$1² is a parameter in method printParamsImpl

只是不知道错误消息是什么意思。

观看现场演示

标签: scalascala-macrosscala-3

解决方案


该错误似乎源于使用scala.quoted.quotes,如下所示:

transparent inline def quotes(using inline q: Quotes): q.type = q

这似乎有效,因为您拥有(using Quotes). 但是,它似乎无法分配稳定的单一类型( the q.type),因为Quotes未命名。

如果将其更改为(using q: Quotes), 然后import q.reflect._,则此特定错误会消失(尽管随后会显示示例中的其他一些错误)。

这是一个完成的示例,它完成了我认为您正在尝试做的事情:

  def printParamsImpl[A](using q: Quotes)(using Type[A]): Expr[() => Unit] = {
    import q.reflect._
    
    val paramNames = Expr.ofList {
      // In each declared method, get a list of the names of each parameter in the first parameter list.
      // Flatten those into a single list of String expressions
      TypeRepr.of[A].typeSymbol.declaredMethods.collect {
        case m if m.paramSymss.size == 1 =>
          val params = m.paramSymss.head
          params.map {  p =>
            Literal(StringConstant(p.name)).asExprOf[String]
          }
      }.flatten
    }

    '{
    () => println(${paramNames})
    }
  }

  inline def foo[A]: () => Unit = ${printParamsImpl[A]}

这里有一个 Scastie ,但它仍然无法运行 - 您不能在定义的同一编译单元中调用宏。

但是,如果您使用主源下的定义和测试源下的调用(例如,在一个App对象中)创建一个项目,您将能够运行它sbt test:run(因为主源和测试源是单独的编译运行)。


推荐阅读