在 GitHub 上編輯此頁面

不透明類型別名:更多詳細資料

語法

Modifier          ::=  ...
                    |  ‘opaque’

opaque軟修改器。當它不在定義關鍵字前面時,它仍可用作一般識別碼。

不透明類型別名必須是類別、特質或物件的成員,或定義在頂層。它們無法定義在區域區塊中。

類型檢查

(單態)不透明類型別名的一般形式為

opaque type T >: L <: U = R

其中下界 L 和上界 U 可能遺失,如果遺失,則假設它們分別為 scala.Nothingscala.Any。如果給定界線,則會檢查右手邊 R 是否符合它們,即 L <: RR <: U。不透明類型別名不支援 F 界線:T 不允許出現在 LU 中。

在別名的定義範圍內,別名是透明的:T 被視為 R 的正常別名。在範圍外,別名被視為抽象類型

type T >: L <: U

如果在物件中定義不透明類型別名,則會出現特殊情況。範例

object o:
  opaque type T = R

在這種情況下,我們在物件內部(也適用於非不透明類型)有 o.T 等於 T 或其展開形式 o.this.T。這裡的相等性理解為相互子類型化,即 o.T <: o.this.To.this.T <: o.T。此外,根據不透明類型別名的規則,我們有 o.this.T 等於 R。這兩個相等性組成。也就是說,在 o 內部,也知道 o.T 等於 R。這表示以下程式碼類型檢查

object o:
  opaque type T = Int
  val x: Int = id(2)
def id(x: o.T): o.T = x

不透明類型別名不能是 private,也不能在子類別中覆寫。不透明類型別名不能將內容函式類型作為右側。

不透明類型的類型參數

不透明類型別名可以有一個類型參數清單。下列別名格式正確

opaque type F[T] = (T, T)
opaque type G = [T] =>> List[T]

但下列別名格式不正確

opaque type BadF[T] = [U] =>> (T, U)
opaque type BadG = [T] =>> [U] =>> (T, U)

相等性的轉換

使用 ==!= 比較兩個不透明類型的值通常會使用通用相等性,除非為該類型定義了另一個重載的 ==!= 算子。為了避免封裝,此操作會在類型檢查後對應到在基礎類型上定義的(不)相等性算子。例如,

opaque type T = Int

  ...
  val x: T
  val y: T
  x == y    // uses Int equality for the comparison.

頂層不透明類型

頂層的不透明類型別名在它出現的原始檔中的所有其他頂層定義中都是透明的,但在巢狀物件和類別以及所有其他原始檔中是不透明的。範例

// in test1.scala
opaque type A = String
val x: A = "abc"

object obj:
  val y: A = "abc"  // error: found: "abc", required: A

// in test2.scala
def z: String = x   // error: found: A, required: String

如果回想一下頂層定義會放置在它們自己的合成物件中,這種行為就會變得清楚。例如,test1.scala 中的程式碼會擴充為

object test1$package:
  opaque type A = String
  val x: A = "abc"

object obj:
  val y: A = "abc"  // error: cannot assign "abc" to opaque type alias A

不透明類型別名 A 在其範圍內是透明的,其中包括 x 的定義,但不包括 objy 的定義。

與 SIP 35 的關係

Scala 3 中的不透明類型是 Scala SIP 35 中所述內容的演變。

與此 SIP 中所述狀態相比,差異在於

  1. 不透明類型別名不能再在局部語句序列中定義。
  2. 不透明類型別名可見的範圍現在是其定義的整個範圍,而不再僅僅是一個伴隨物件。
  3. 不透明類型別名的伴隨物件概念已被捨棄。
  4. 不透明類型別名可以有界限。
  5. 涉及不透明類型別名的類型相等概念已得到澄清。相對於 SIP 35 的先前實作,它已被加強。