未來,Scala 3 將使用 _
底線符號作為類型 lambda 中的佔位符,就像目前在(一般)項級 lambda 中使用底線作為佔位符一樣。
新的類型 lambda 語法並未預設啟用,若要啟用,請使用編譯器標記 -Ykind-projector:underscores
。請注意,啟用底線類型 lambda 會停用 _
作為萬用字元的使用,您只能使用 ?
符號撰寫萬用字元。
如果您希望為 Scala 2 和 Scala 3 交叉編譯專案,同時對兩者都使用底線類型 lambda,您可以從 kind-projector 版本 0.13.0
以上和 Scala 2 版本 2.13.6
和 2.12.14
開始執行此操作。若要啟用,請將編譯器標記 -Xsource:3 -P:kind-projector:underscore-placeholders
新增到您的建置。與 Scala 3 一樣,這會停用 _
作為萬用字元的使用,但標記 -Xsource:3
將允許您使用 ?
符號取代它。
以下 sbt
組態將設定正確的旗標以使用新語法進行跨編譯
ThisBuild / scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((3, _)) => Seq("-Ykind-projector:underscores")
case Some((2, 12 | 13)) => Seq("-Xsource:3", "-P:kind-projector:underscore-placeholders")
}
}
移轉到新語法
要在已啟用 kind-projector 的現有程式碼中使用底線作為類型 lambda,請將 *
或 ?
類型 lambda 佔位符替換為 _
。
反過來,您還必須將 _
作為萬用字元的所有用法改寫為使用 ?
符號。
例如,萬用字元的以下用法
def getWidget(widgets: Set[_ <: Widget], name: String): Option[Widget] = widgets.find(_.name == name)
必須改寫為
def getWidget(widgets: Set[? <: Widget], name: String): Option[Widget] = widgets.find(_.name == name)
以及 kind-projector 的 *
佔位符的以下用法
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double]
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A]
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
必須改寫為
Tuple2[_, Double] // equivalent to: type R[A] = Tuple2[A, Double]
Either[Int, +_] // equivalent to: type R[+A] = Either[Int, A]
Function2[-_, Long, +_] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
編譯現有程式碼
即使不移轉到底線類型 lambda,您可能仍可以在沒有變更的情況下使用 Scala 3 編譯大部分程式碼。
使用旗標 -Ykind-projector
來啟用對 *
為基礎的類型 lambda 的支援(不啟用底線類型 lambda),以下形式現在將編譯
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double]
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A]
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B]
改寫不相容的結構
Scala 3 的 -Ykind-projector
和 -Ykind-projector:underscores
僅實作 kind-projector
語法的子集,特別是它們不實作
- 高階類型 lambda 佔位符
- 高階命名類型 lambda 參數
Lambda
關鍵字(λ
仍受支援)
您必須改寫以下所有形式
// classic
EitherT[*[_], Int, *] // equivalent to: type R[F[_], B] = EitherT[F, Int, B]
// underscores
EitherT[_[_], Int, _] // equivalent to: type R[F[_], B] = EitherT[F, Int, B]
// named λ
λ[(F[_], A) => EitherT[F, Int, A]]
// named Lambda
Lambda[(F[_], A) => EitherT[F, Int, A]]
成以下長格式才能使用 Scala 3 進行跨編譯
type MyLambda[F[_], A] = EitherT[F, Int, A]
MyLambda
或者,如果您不需要進行跨編譯,可以使用 Scala 3 的 原生類型 lambda
[F[_], A] =>> EitherT[F, Int, A]
對於 Lambda
,您必須改寫以下形式
Lambda[(`+E`, `+A`) => Either[E, A]]
成以下形式才能進行跨編譯
λ[(`+E`, `+A`) => Either[E, A]]
或者改成 Scala 3 類型 lambda
[E, A] =>> Either[E, A]
注意:Scala 3 類型 lambda 不再需要參數上的 -
或 +
變異標記,這些標記現在會推論。