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]

此頁面的貢獻者