此文件頁面特定於 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
請務必注意,在預設萃取出 Name
、TermName
或 Modifiers
的位置,不會執行 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)
}
}
在此必須注意一些細微差別
-
類似於
Liftable
,Unliftable
在伴隨物件中定義一個輔助apply
函式,以簡化Unliftable
實例的建立。它採用類型參數T
,以及部分函式PartialFunction[Tree, T]
,並回傳Unliftable[T]
。在部分函式已定義的所有輸入中,預期它會無條件回傳T
的實例。 -
我們僅為執行時期宇宙定義
Unliftable
,它不會在巨集中提供。(請參閱 分享不同宇宙的 liftable 實作) -
此不可提升函數中使用的模式僅會比對以
_root_
開頭的Point
的完全限定參照。它不會比對參照的其他可能形狀;它們必須手動指定。這個問題是由於缺乏 衛生 造成的。 -
此模式僅會比對具有文字
Int
參數的樹狀結構。它不會對可能評估為Int
的其他表達式運作。
標準不可提升函數
類型 | 表示法 | 值 |
---|---|---|
Byte 、Short 、Int 、Long |
q"0" |
0 |
Float |
q"0.0" |
0.0 |
Double |
q"0.0D" |
0.0D |
布林 |
q"true" 、q"false" |
true 、false |
字元 |
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。所有類型參數本身都必須是不可提升函數。