Scala 導覽

單例物件

語言

物件是一個僅有一個實例的類別。它在被參照時會延遲建立,就像延遲 val 一樣。

作為頂層值,物件是單例。

作為封閉類別的成員或作為局部值,它的行為完全就像延遲 val。

定義單例物件

物件是一個值。物件的定義看起來像一個類別,但使用關鍵字 object

object Box

以下是具有方法的物件範例

package logging

object Logger {
  def info(message: String): Unit = println(s"INFO: $message")
}
package logging

object Logger:
  def info(message: String): Unit = println(s"INFO: $message")

方法 info 可以從程式中的任何地方匯入。建立像這樣的實用程式方法是單例物件的常見使用案例。

讓我們看看如何在另一個套件中使用 info

import logging.Logger.info

class Project(name: String, daysToComplete: Int)

class Test {
  val project1 = new Project("TPS Reports", 1)
  val project2 = new Project("Website redesign", 5)
  info("Created projects")  // Prints "INFO: Created projects"
}
import logging.Logger.info

class Project(name: String, daysToComplete: Int)

class Test:
  val project1 = Project("TPS Reports", 1)
  val project2 = Project("Website redesign", 5)
  info("Created projects")  // Prints "INFO: Created projects"

info 方法會因為匯入陳述式 import logging.Logger.info 而可見。

匯入需要一個到匯入符號的「穩定路徑」,而物件是一個穩定路徑。

注意:如果 object 不是頂層,而是巢狀在另一個類別或物件中,則物件會像任何其他成員一樣「路徑依賴」。這表示給定兩種飲料,class Milkclass OrangeJuice,類別成員 object NutritionInfo 「依賴」於封閉實例,可能是牛奶或柳橙汁。 milk.NutritionInfooj.NutritionInfo 完全不同。

伴隨物件

與類別同名的物件稱為伴隨物件。相反地,類別是物件的伴隨類別。伴隨類別或物件可以存取其伴隨的私有成員。對伴隨類別的實例不特定的方法和值,請使用伴隨物件。

import scala.math.{Pi, pow}

case class Circle(radius: Double) {
  import Circle._
  def area: Double = calculateArea(radius)
}

object Circle {
  private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
}

val circle1 = Circle(5.0)

circle1.area
import scala.math.{Pi, pow}

case class Circle(radius: Double):
  import Circle.*
  def area: Double = calculateArea(radius)

object Circle:
  private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)


val circle1 = Circle(5.0)

circle1.area

class Circle 有成員 area,這是特定於每個實體,而單例 object Circle 有方法 calculateArea,每個實體都可以使用。

伴生物件也可以包含工廠方法

class Email(val username: String, val domainName: String)

object Email {
  def fromString(emailString: String): Option[Email] = {
    emailString.split('@') match {
      case Array(a, b) => Some(new Email(a, b))
      case _ => None
    }
  }
}

val scalaCenterEmail = Email.fromString("[email protected]")
scalaCenterEmail match {
  case Some(email) => println(
    s"""Registered an email
       |Username: ${email.username}
       |Domain name: ${email.domainName}
     """.stripMargin)
  case None => println("Error: could not parse email")
}
class Email(val username: String, val domainName: String)

object Email:
  def fromString(emailString: String): Option[Email] = 
    emailString.split('@') match
      case Array(a, b) => Some(Email(a, b))
      case _ => None

val scalaCenterEmail = Email.fromString("[email protected]")
scalaCenterEmail match
  case Some(email) => println(
    s"""Registered an email
       |Username: ${email.username}
       |Domain name: ${email.domainName}
     """.stripMargin)
  case None => println("Error: could not parse email")

object Email 包含一個工廠 fromString,它會從字串建立一個 Email 實體。如果發生剖析錯誤,我們會將它傳回為 Option[Email]

注意:如果一個類別或物件有伴生,兩者都必須定義在同一個檔案中。要在 REPL 中定義伴生,請在同一行定義它們,或輸入 :paste 模式。

給 Java 程式設計師的注意事項

Java 中的 static 成員在 Scala 中建模為伴生物件的普通成員。

從 Java 程式碼使用伴生物件時,這些成員會定義在具有 static 修飾詞的伴生類別中。這稱為靜態轉發。即使您自己沒有定義伴生類別,也會發生這種情況。

更多資源

此頁面的貢獻者