2014-10-29 92 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