簡體   English   中英

接受任何在traala中擴展trait作為參數的case類

[英]Accept any case class which extends a trait as argument in scala

我需要一個函數來接受任何擴展特征的case類。 舉個例子

假設有一個特征

trait Action {
    def execute(param: Parameters)
}

並且可以傳遞以下參數,具體取決於它的操作類型

trait Parameters
case class A(x: String, y: Double) extends Parameters
case class B(x: Int, y:String, z: Double) extends Parameters

用戶應該能夠指定它想要的參數

class Action1 extends Action {
    override def execute(param: A)
}

class Action2 extends Action {
    override def execute(param: B)
}

在打電話的時候

def run(t: Action) {
    t.execute(new A("a", 1.0))
}

怎么做到這一點? 當我實現Action1時,它表示我將得到我們無法覆蓋的錯誤,因為trait表示execute方法接受Parameters,但是在重寫時,我們需要一個擴展Parameters的類。

一種方法是參數化Action

trait Action[T <: Parameters] {
  def execute(param: T)
}

然后

class Action1 extends Action[A] {
  override def execute(param: A)
}

class Action2 extends Action[B] {
  override def execute(param: B)
}

def run[T <: Parameters](t: Action[T], param: T) {
  t.execute(param)
}

// You don't need new for a case class
run(new Action1, A("a", 1.0))

你必須在這里修改一下run ,因為你不能通過單獨的子類化來獲得你所要求的。 參數類型是逆變的 ,這意味着函數A => T的函數是函數Parameters => T超類 這是因為雖然類型A任何參數都適用於A => TParameters => T ,但只有一些參數類型的Parameters適用於A => T而所有這些Parameters => T都適用於Parameters => T

你需要考慮的是為什么你需要你的Action來開始execute方法。 可能你的代碼中有其他類似的東西:

def executeAll(actions: Seq[Action], params: Parameters) = 
    actions.foreach { _.execute(params) }

請注意,此處您的actions列表可以包含不同類型的操作。 如果其中一些除了類型A的參數,並且有些需要它是B ,它將無法工作,因為你的params參數不能同時存在。

出於這個原因,你不能覆蓋一個方法來在子類中采用不同的參數類型(實際上,你可以,但是類型必須是原始類型的超類,而不是子類。他們說函數是逆變的這個reas的參數類型,但我離題了。

如果您的Action1Action2能跟參數一般,通過特征界面處理,而不需要他們是特定類型的,那么解決方法很簡單:只要改變你的首要方法的聲明是override def execute(params: Parameters)

如果不是這種情況,並且Action1只能處理類型A參數,那么(1)可能(雖然,不一定)你的設計有問題,(2)你必須使用參數化解決方案,正如另一個答案所示。 但是你必須改變所有處理Action的地方:

def executeAll[T <: Parameters](actions: Seq[Action[T]], params: T) = ...

此聲明約束params參數的類型以匹配列表中的操作所期望的內容,因此不會錯誤地使用B調用Action1.execute

現在,正如你在其他答案的評論中提到的那樣,你不能混合不同類型的動作,因為它沒有意義:它們本質上是不同的類。 如果您不打算使用execute方法,並且只想傳遞一些代碼周圍的不同操作列表,則可以使用通配符語法:

val actions: List[Action[_] = List(Action1(...), Action2(...))

同樣,此列表可以作為任何類型的操作的通用容器,但是您不能使用它來一般地應用execute方法,因為這將要求參數同時具有不同類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM