Scala 導覽

使用 Mixin 進行類別組合

語言

Mixin 是用於組合類別的特質。

abstract class A {
  val message: String
}
class B extends A {
  val message = "I'm an instance of class B"
}
trait C extends A {
  def loudMessage = message.toUpperCase()
}
class D extends B with C

val d = new D
println(d.message)  // I'm an instance of class B
println(d.loudMessage)  // I'M AN INSTANCE OF CLASS B

類別 D 有超級類別 B 和 mixin C。類別只能有一個超級類別,但可以有多個 mixin(分別使用關鍵字 extendswith)。Mixin 和超級類別可以有相同的超類別。

abstract class A:
  val message: String
class B extends A:
  val message = "I'm an instance of class B"
trait C extends A:
  def loudMessage = message.toUpperCase()
class D extends B, C

val d = D()
println(d.message)  // I'm an instance of class B
println(d.loudMessage)  // I'M AN INSTANCE OF CLASS B

類別 D 有超級類別 B 和 mixin C。類別只能有一個超級類別,但可以有多個 mixin(分別使用關鍵字 extends 和分隔符號 ,)。Mixin 和超級類別可以有相同的超類別。

現在讓我們來看一個從抽象類別開始的更有趣的範例

abstract class AbsIterator {
  type T
  def hasNext: Boolean
  def next(): T
}
abstract class AbsIterator:
  type T
  def hasNext: Boolean
  def next(): T

類別有一個抽象類型 T 和標準的迭代器方法。

接下來,我們將實作一個具體類別(所有抽象成員 ThasNextnext 都已實作)

class StringIterator(s: String) extends AbsIterator {
  type T = Char
  private var i = 0
  def hasNext = i < s.length
  def next() = {
    val ch = s charAt i
    i += 1
    ch
  }
}
class StringIterator(s: String) extends AbsIterator:
  type T = Char
  private var i = 0
  def hasNext = i < s.length
  def next() =
    val ch = s charAt i
    i += 1
    ch

StringIterator 會取得一個 String,可用於在 String 上進行迭代(例如,查看 String 是否包含某個字元)。

現在讓我們建立一個特質,它也延伸 AbsIterator

trait RichIterator extends AbsIterator {
  def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}

這個特質透過持續呼叫提供的函式 f: T => Unit 來實作 foreach,只要有進一步的元素(while (hasNext)),就會在下一元素(next())上呼叫它。因為 RichIterator 是特質,所以它不需要實作 AbsIterator 的抽象成員。

trait RichIterator extends AbsIterator:
  def foreach(f: T => Unit): Unit = while hasNext do f(next())

此特質透過持續呼叫提供的函數 f: T => Unit 來實作 foreach,只要有進一步的元素(while hasNext),就會在下一元素(next())上執行。由於 RichIterator 是特質,因此它不需要實作 AbsIterator 的抽象成員。

我們想要將 StringIteratorRichIterator 的功能結合到單一類別中。

class RichStringIter extends StringIterator("Scala") with RichIterator
val richStringIter = new RichStringIter
richStringIter.foreach(println)
class RichStringIter extends StringIterator("Scala"), RichIterator
val richStringIter = RichStringIter()
richStringIter.foreach(println)

新的類別 RichStringIter 使用 StringIterator 作為超類別,並使用 RichIterator 作為混入。

使用單一繼承,我們無法達到這種程度的彈性。

此頁面的貢獻者