2012-06-19 81 views
1

例如類型,參數化的課,我有下面的類層次結構:使用默認類型參數

abstract class A { 
    def a() {} 
    def aa() 
} 

class B extends A { 
    def aa() {} 
    def b() 
} 

class C extends A { 
    def aa() {} 
    def c() 
} 

然後,我希望創建一個可以存儲這些類的實例的任意組合的集合類。它將能夠調用常用的方法。並且由於類型參數化,必須提供調用,如果在創建過程中參數化這些類類特定的方法的能力:

object Group { 

    def apply(as: Buffer[A]) = new Group[A](as) 
    def apply[T <: A](as: Buffer[T]) = new Group[T](as) 
} 

class Group[T <: A](as: Buffer[T]) { 

    def a() { as.map(_.a()) } 
    def aa() { as.map(_.aa()) } 

} 

所以Group可以用默認創建的,這樣最通用的類​​型參數:

val groupA = Group(Buffer[A]()) 
groupA.a() //ok 
groupA.aa() //ok 
groupA.b() //error 
groupA.c() //error 

並與A後裔的一個明確參數化時,它可以創建:

val groupB = Group[B](Buffer[B]()) 
groupB.a() //ok 
groupB.aa() //ok 
groupB.b() //ok 
groupB.c() //error 

一第二,如果可能的話,我想創建組時,以某種方式去除[B]不必要的類型規範,因爲它可以從傳遞的緩衝區類型中提取:

val groupB = Group(Buffer[B]()) 

什麼是實現這一點的正確方法功能?可能嗎?也許有更好的架構決定來實現這一目標?

更新:這裏的代碼是僞代碼,我只是不知道如何寫我想要的東西。

更新2:我想,調用類型特定的方法,如b()c()應通過映射來實現:

groupC.as.map(_.c()) 

其是僅可能,如果類型參數化是正確的。這更接近我的想法,但實現的確切方式仍然是一個謎(除了一堆asInstanceOf東西的用法)..

+0

也許使用'Group [C]'的隱式轉換爲具有'c()'方法的東西,它只適用於參數爲「C」的情況? – ziggystar

+0

@ziggystar:也許,但你能舉個例子嗎?我不確定我能否像那樣把握它。 – noncom

回答

2

您可以使用隱式轉換來將方法看似只添加到那些Group的實例用正確的類型參數化。這可以被認爲是pimp my library模式的選擇性版本。

scala> abstract class A { def a() {}; def aa() {} } 
defined class A 

scala> class B extends A {def b() {}} 
defined class B 

scala> class C extends A {def c() {}} 
defined class C 

現在我定義了Group類。請注意0​​的隱式轉換,其中添加了c()方法。這種轉換不適用於例如值爲Group[A]

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

case class Group[T <: A](as: Seq[T]) 
object Group{implicit def forC(gc: Group[C]) = new {def c() {gc.as.map(_.c())}}} 

// Exiting paste mode, now interpreting. 

defined class Group 
defined module Group 

現在讓我們來看看它是否有效。

scala> val groupC = Group(new C :: new C :: Nil) 
groupC: Group[C] = Group(List([email protected], [email protected])) 

scala> groupC.c() //works 

scala> val groupB = Group(new B :: new B :: Nil) 
groupB: Group[B] = Group(List([email protected], [email protected])) 

scala> groupB.c() //fails as expected 
<console>:16: error: value c is not a member of Group[B] 
       groupB.c() 
        ^
+0

這絕對好得多!但是,對不起,我有一些問題=):1)case class由於調用自動創建的'as'方法的便利性,所以只能創建* case *類?2)你提到'c()'方法不會產生任何東西。爲什麼這很重要?你是否認爲這純粹是副作用,這是無法幫助的? 3)我可以在哪裏閱讀更多關於這裏使用的'隱式'形式,以及'new {}'構造的無名類?這個表單是否意味着無名的類實例(?)會繼承組[C]中的內容? – noncom

+0

1)'case'類是方便的;它還會將「應用」添加到手動完成的伴侶。 2)是的,評論有點誤導。我添加了它,因此讀者不會懷疑輸出的位置。沒有辦法,因爲這個方法什麼都不做。你可以在'c()'中做任何你喜歡的事情。 3)該模式被稱爲[* Pimp我的圖書館*](http://www.scalaclass.com/node/14);你也可以命名這個班。除非添加'extends C',否則它不會從'C'繼承。 – ziggystar

+0

非常感謝! – noncom