Scala 3 中的宏

常见问题解答

语言
此文档页面特定于 Scala 3,可能涵盖 Scala 2 中不可用的新概念。 除非另有说明,否则此页面中的所有代码示例都假设您使用的是 Scala 3。

我应该使用哪个 Expr(...)'{...}

如果您可以在编译时使用 Expr(...) 编写代码,则会在编译时进行更多评估。 仅当您确实需要在运行时稍后评估代码时才使用 '{...},通常是因为它依赖于运行时值。

Expr(true)'{true} 之间哪个更好?

所有包含基本类型值的引号都被优化为 Expr.apply。 在您的项目中选择一个,并坚持使用单一符号以避免混淆。

如何从 Expr 中获取值?

如果表达式表示一个值,可以使用 .value.valueOrAbortExpr.unapply

如何获取 Expr 的精确类型?

我们可以使用以下模式匹配获取 Expr 的精确类型 (Type)

val x: Expr[X] = ...
x match
  case '{ $x: t } =>
    // `x: Expr[X & t]` where `t` is the precise type of `x`

如何调用元组类型的所有类型?

如果我有一个类型 (T1, T2, ...),如何生成 (summon[T1], summon[T2], ...) 的项,或者获取带有调用值的单个表达式?

根据您的用例,调用它们的方式会有所不同。特别是,您需要的代码取决于您想要的输出类型 (Expr[Tuple]List[Expr[Any]] 或其他类型) 以及您需要如何报告错误。以下两个示例应该为您提供这两种代码变体的基本框架。

  def summonAllInList[T](using Type[T])(using Quotes): List[Expr[Any]] = {
    Type.of[T] match
      case '[ head *: tail ] =>
        Expr.summon[head] match
          case Some(headExpr) => headExpr :: summonAllInList[tail]
          case _ => quotes.reflect.report.throwError(s"Could not summon ${Type.show[head]}")
      case '[ EmptyTuple ] => Nil
      case _ => quotes.reflect.report.throwError(s"Could not `summonAllInList` of tuple with unknown size: ${Type.show[T]}")
  }
  def summonAll[T](using Type[T])(using Quotes): Option[Expr[Tuple]]] = {
    Type.of[T] match
      case '[ head *: tail ] =>
        for headExpr <- Expr.summon[head]
            tailExpr <- summonAll[tail]
        yield '{ headExpr *: tailExpr }
      case '[ EmptyTuple ] => Some('{ EmptyTuple })
      case _ => None
  }

如何为静态未知类型调用表达式?

您可以从 TypeReprType 调用表达式,如下所示。

如果您有 TypeRepr,请使用

val tpe: TypeRepr = ...
Implicits.search(tpe) match
  case result: ImplicitSearchSuccess => result.tree
  case _ =>

相反,如果您有 Type[_],请使用

val tpe: Type[_] = ...
tpe match
  // (1) Use `a` as the name of the unknown type and (2) bring a given `Type[a]` into scope
  case '[a] => Expr.summon[a]

本页贡献者