準引號

取消提升

語言
此文件頁面特定於 Scala 2 中提供的功能,這些功能已在 Scala 3 中移除或由替代方案取代。除非另有說明,此頁面中的所有程式碼範例都假設您使用的是 Scala 2。

Denys Shabalin 實驗性

取消提升是 提升 的反向操作:它會取得一棵樹並從中還原一個值

trait Unliftable[T] {
  def unapply(tree: Tree): Option[T]
}

由於樹狀結構可能無法代表我們的資料類型,因此 unapply 的回傳類型是 Option[T],而非僅是 T。此簽章讓 Unliftable 實例易於用作萃取器。

當給定資料類型有 Unliftable 的隱式實例時,你可以使用歸因語法進行樣式比對

scala> val q"${left: Int} + ${right: Int}" = q"2 + 2"
left: Int = 2
right: Int = 2

scala> left + right
res4: Int = 4

請務必注意,在預設萃取出 NameTermNameModifiers 的位置,不會執行 unlifting

scala> val q"foo.${bar: Int}" = q"foo.bar"
<console>:29: error: pattern type is incompatible with expected type;
 found   : Int
 required: universe.NameApi
       val q"foo.${bar: Int}" = q"foo.bar"
                        ^

你也可以成功結合 unquote splicing 和 unlifting

scala> val q"f(..${ints: List[Int]})" = q"f(1, 2, 3)"
ints: List[Int] = List(1, 2, 3)

scala> val q"f(...${intss: List[List[Int]]})" = q"f(1, 2, 3)(4, 5)(6)"
intss: List[List[Int]] = List(List(1, 2, 3), List(4, 5), List(6))

類似於 lifting,這會逐一 unlift 函式的引數,並將結果包裝到 List 中。

自行定義

類似於 liftable,你可以定義自己的 unliftable

package Points

import scala.universe._

case class Point(x: Int, y: Int)
object Point {
  implicit val unliftPoint = Unliftable[points.Point] {
    case q"_root_.points.Point(${x: Int}, ${y: Int})" => Point(x, y)
  }
}

在此必須注意一些細微差別

  1. 類似於 LiftableUnliftable 在伴隨物件中定義一個輔助 apply 函式,以簡化 Unliftable 實例的建立。它採用類型參數 T,以及部分函式 PartialFunction[Tree, T],並回傳 Unliftable[T]。在部分函式已定義的所有輸入中,預期它會無條件回傳 T 的實例。

  2. 我們僅為執行時期宇宙定義 Unliftable,它不會在巨集中提供。(請參閱 分享不同宇宙的 liftable 實作

  3. 此不可提升函數中使用的模式僅會比對以 _root_ 開頭的 Point 的完全限定參照。它不會比對參照的其他可能形狀;它們必須手動指定。這個問題是由於缺乏 衛生 造成的。

  4. 此模式僅會比對具有文字 Int 參數的樹狀結構。它不會對可能評估為 Int 的其他表達式運作。

標準不可提升函數

類型 表示法
ByteShortIntLong q"0" 0
Float q"0.0" 0.0
Double q"0.0D" 0.0D
布林 q"true"q"false" truefalse
字元 q"'c'" 'c'
單位 q"()" ()
字串 q""" "字串" """ "字串"
符號 q"'符號" '符號
術語名稱 q"foo"pq"foo" TermName("foo")
類型名稱 tq"foo" TypeName("foo")
類型 tt: TypeTree tt.tpe
常數 lit: Literal lit.value
TupleN[...] * q"(1, 2)" (1, 2)

(*) 元組的不可提升函數定義於 [2, 22] 範圍內的所有 N。所有類型參數本身都必須是不可提升函數。

此頁面的貢獻者