[英]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 => T
和Parameters => 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的參數類型,但我離題了。
如果您的Action1
和Action2
能跟參數一般,通過特征界面處理,而不需要他們是特定類型的,那么解決方法很簡單:只要改變你的首要方法的聲明是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.