Scala 導覽

抽象類型成員

語言

抽象類型,例如特質和抽象類別,反過來也可以有抽象類型成員。這表示具體實作會定義實際類型。以下是一個範例

trait Buffer {
  type T
  val element: T
}
trait Buffer:
  type T
  val element: T

我們在此定義了一個抽象 類型 T。它用來描述 元素 的類型。我們可以在抽象類別中延伸這個特質,為 T 新增一個上層類型邊界,以使其更具體。

abstract class SeqBuffer extends Buffer {
  type U
  type T <: Seq[U]
  def length = element.length
}
abstract class SeqBuffer extends Buffer:
  type U
  type T <: Seq[U]
  def length = element.length

請注意,我們如何能在 T 的上層類型邊界規格中使用另一個抽象類型 U。這個 類別 SeqBuffer 讓我們能夠透過聲明類型 T 必須是新抽象類型 USeq[U] 子類型,來儲存緩衝區中的序列。

具有抽象類型成員的特質或 類別 通常與匿名類別實例化結合使用。為了說明這一點,我們現在來看一個處理參考整數清單的序列緩衝區的程式

abstract class IntSeqBuffer extends SeqBuffer {
  type U = Int
}

def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
  new IntSeqBuffer {
    type T = List[U]
    val element = List(elem1, elem2)
  }
val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
abstract class IntSeqBuffer extends SeqBuffer:
  type U = Int

def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
  new IntSeqBuffer:
    type T = List[U]
    val element = List(elem1, elem2)

val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)

在這裡,工廠 newIntSeqBuf 使用 IntSeqBuffer 的匿名類別實作(即 new IntSeqBuffer)來設定抽象類型 T 為具體類型 List[Int]

也可以將抽象類型成員轉換為類別的類型參數,反之亦然。以下是僅使用類型參數的上述程式碼版本

abstract class Buffer[+T] {
  val element: T
}
abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
  def length = element.length
}

def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
  new SeqBuffer[Int, List[Int]] {
    val element = List(e1, e2)
  }

val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
abstract class Buffer[+T]:
  val element: T

abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T]:
  def length = element.length

def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
  new SeqBuffer[Int, List[Int]]:
    val element = List(e1, e2)

val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)

請注意,我們必須在這裡使用 變異註解+T <: Seq[U]),才能隱藏從方法 newIntSeqBuf 傳回的物件的具體序列實作類型。此外,有些情況無法將抽象類型成員替換為類型參數。

此頁面的貢獻者