Scala trait函数:返回派生类型的实例

时间:2014-10-29 12:16:54

标签: scala traits

我有一个看起来像这样的特质书

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时,我需要Fictionfiction1。我知道一种方法是做.map( _.asInstanceOf[ Fiction ] )。但是,有没有办法完全避免这种情况?

实际上,我意识到错误的方法是能够为Fiction定义一个扩展Book的伴随对象,以便我可以在该对象上调用getAll(然而,在这种情况下,我不确定如何将返回序列中的各个元素转换为Fiction类的实例,因为Fiction类将不再来自Book。 我应该有两个不同名称的Book特征吗?一个是这些对象的超级,另一个是这些类的超类?

编辑:@Travis Brown的回复解决了我最初的问题。如果有人对如何使用伴侣对象而不是类实例进行处理,那就太棒了!

1 个答案:

答案 0 :(得分:9)

这或多或少是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 polymorphism has its detractors,有一些需要注意的问题,但它在Scala和Java中都是一个相当广泛使用的模式。