Scala - 特性



特性封裝了方法和欄位的定義,然後可以透過將它們混合到類中來重用。與類繼承不同,在類繼承中每個類都必須從一個超類繼承,一個類可以混合任意數量的特性。

特性用於透過指定支援方法的簽名來定義物件型別。Scala 還允許特性被部分實現,但特性不能有建構函式引數。

特性定義看起來就像類定義,只是它使用關鍵字trait。以下是特性的基本示例語法。

語法

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

此特性包含兩個方法isEqualisNotEqual。在這裡,我們沒有為 isEqual 提供任何實現,而另一個方法有其實現。擴充套件特性的子類可以為未實現的方法提供實現。因此,特性非常類似於我們在 Java 中擁有的抽象類

讓我們假設一個特性Equal包含兩個方法isEqual()isNotEqual() 的示例。特性Equal包含一個已實現的方法,即isEqual(),因此當用戶定義的類Point擴充套件特性Equal時,應在Point類中提供isEqual()方法的實現。

這裡需要了解 Scala 的兩個重要方法,它們在下面的示例中使用。

  • obj.isInstanceOf [Point] 用於檢查 obj 和 Point 的型別是否相同。

  • obj.asInstanceOf [Point] 表示透過獲取物件 obj 型別並將其作為 Point 型別返回來進行精確轉換。

嘗試以下示例程式來實現特性。

示例

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

class Point(xc: Int, yc: Int) extends Equal {
   var x: Int = xc
   var y: Int = yc
   
   def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == y
}

object Demo {
   def main(args: Array[String]) {
      val p1 = new Point(2, 3)
      val p2 = new Point(2, 4)
      val p3 = new Point(3, 3)

      println(p1.isNotEqual(p2))
      println(p1.isNotEqual(p3))
      println(p1.isNotEqual(2))
   }
}

將上述程式儲存到Demo.scala中。以下命令用於編譯和執行此程式。

命令

\>scalac Demo.scala
\>scala Demo

輸出

true
false
true

值類和通用特性

值類是 Scala 中一種新的機制,用於避免分配執行時物件。它包含一個只有一個val引數的主建構函式。它僅包含方法 (def),不允許使用 var、val、巢狀類、特性或物件。值類不能被另一個類擴充套件。這可以透過使用 AnyVal 擴充套件值類來實現。自定義資料型別的型別安全,沒有執行時開銷。

讓我們以值類 Weight、Height、Email、Age 等為例。對於所有這些示例,不需要在應用程式中分配記憶體。

值類不允許擴充套件特性。為了允許值類擴充套件特性,引入了通用特性,它擴充套件了Any

示例

trait Printable extends Any {
   def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable

object Demo {
   def main(args: Array[String]) {
      val w = new Wrapper(3)
      w.print() // actually requires instantiating a Wrapper instance
   }
}

將上述程式儲存到Demo.scala中。以下命令用於編譯和執行此程式。

命令

\>scalac Demo.scala
\>scala Demo

輸出

它將為您提供 Wrapper 類的雜湊碼。

Wrapper@13

何時使用特性?

沒有硬性規定,但以下是一些需要考慮的指導原則:

  • 如果行為不會被重用,則將其設為具體類。畢竟它不是可重用的行為。

  • 如果它可能在多個不相關的類中重用,則將其設為特性。只有特性才能混合到類層次結構的不同部分。

  • 如果要從 Java 程式碼中繼承它,請使用抽象類。

  • 如果計劃以編譯的形式分發它,並且您期望外部組編寫從中繼承類的類,那麼您可能會傾向於使用抽象類。

  • 如果效率非常重要,請傾向於使用類。

廣告