2014-10-29 81 views
4

的例子中,我有一個特質書,看起來像這樣斯卡拉性狀功能:返回派生類型

trait Book{ 
val sqlTableName; 
def getAll: Seq[ Book ] = { magicSQLFn($"SELECT * FROM $sqlTableName") } 
} 

我有兩個派生類型:

class Fiction extends Book{ val sqlTableName = "fiction" } 
class NonFiction extends Book{ val sqlTableName = "nonfiction"); 

我需要得到Seq[Fiction]當我叫getAll例如Fiction,例如fiction1。我知道一種方法是做.map(_.asInstanceOf[ Fiction ])。但是,有沒有辦法完全避免這種情況?

其實,我實現了更少的錯誤的方式做將能夠定義一個同伴對象Fiction擴展Book,這樣我可以在該對象上調用getAll(而不是做的一個實例),但是,在這種情況下,我不知道如何將返回序列中的單個元素轉換爲Fiction類的實例,因爲Fiction類不會再從Book派生。 我應該有兩個不同名字的Book特質嗎?一個是這些對象的超類,另一個是這些類的超類?

編輯:@Travis布朗的答覆解決了我最初的問題。如果任何人有關於如何使用伴隨對象而不是類實例來處理這個問題的評論,那也會很棒!

回答

7

這或多或少是經典的使用情況F-bounded polymorphism,它允許你指的是特定亞型的超方法:

trait Book[B <: Book[B]] { 
    val sqlTableName; 
    def getAll: Seq[B] = { magicSQLFn($"SELECT * FROM $sqlTableName") } 
} 

class Fiction extends Book[Fiction] { val sqlTableName = "fiction" } 
class NonFiction extends Book[NonFiction] { val sqlTableName = "nonfiction") 

(這裏假設你的magicSQLFn會返回一些與適當的靜態類型,但它是神奇的,畢竟。)

˚F -bounded多態性has its detractors,有問題需要提防,但它在Scala和Java的一個相當廣泛的應用模式。

+0

謝謝!對於如何通過在伴隨對象上調用getAll來處理此問題,而不是在類實例上有什麼意見? – 0fnt 2014-10-29 13:10:17

+0

不確定我明白爲什麼在'Fiction'伴侶對象上定義'getAll'意味着'Fiction'不能擴展'Book'?這可能值得跟進。 – 2014-10-29 13:14:17

+0

我想我錯了。謝謝你糾正我。 – 0fnt 2014-10-29 16:06:03