在 GitHub 上編輯此頁面

特質參數

Scala 3 允許特質有參數,就像類別有參數一樣。

trait Greeting(val name: String):
  def msg = s"How are you, $name"

class C extends Greeting("Bob"):
  println(msg)

在初始化特質之前,會立即評估特質的引數。

特質參數的一個潛在問題是如何防止歧義。例如,您可能會嘗試使用不同的參數來擴充 Greeting 兩次。

class D extends C, Greeting("Bill") // error: parameter passed twice

這應該印出「Bob」還是「Bill」?事實上,這個程式是非法的,因為它違反了特質參數的第二個規則

  1. 如果類別 C 擴充參數化特質 T,而其超類別沒有,則 C 必須傳遞引數給 T

  2. 如果類別 C 擴充參數化特質 T,而其超類別也有,則 C 不能傳遞引數給 T

  3. 特質絕不可將參數傳遞給父特質。

以下是一個擴充參數化特質 Greeting 的特質。

trait FormalGreeting extends Greeting:
  override def msg = s"How do you do, $name"

正如要求所述,沒有參數傳遞給 Greeting。然而,在定義擴充 FormalGreeting 的類別時,這會造成問題

class E extends FormalGreeting // error: missing arguments for `Greeting`.

撰寫 E 的正確方式是同時擴充 GreetingFormalGreeting(順序不拘)

class E extends Greeting("Bob"), FormalGreeting

具有內容參數的特質

如果遺失的特質只包含 內容參數,則此「需要明確擴充」規則會放寬。在這種情況下,特質參考會隱含插入為具有推斷參數的附加父項。例如,以下是一個問候語變體,其中受話者是類型為 ImpliedName 的內容參數

case class ImpliedName(name: String):
  override def toString = name

trait ImpliedGreeting(using val iname: ImpliedName):
  def msg = s"How are you, $iname"

trait ImpliedFormalGreeting extends ImpliedGreeting:
  override def msg = s"How do you do, $iname"

class F(using iname: ImpliedName) extends ImpliedFormalGreeting

最後一行中 F 的定義會隱含擴充為

class F(using iname: ImpliedName) extends
  Object,
  ImpliedGreeting(using iname),
  ImpliedFormalGreeting

請注意插入的對未明確提及的超級特質 ImpliedGreeting 的參考。

參考

如需更多資訊,請參閱 Scala SIP 25