Scala:强制类型参数是一个案例类

时间:2016-10-23 12:41:57

标签: scala

我有一个抽象类Model,我从中创建了案例类:

abstract class Model
case class User(.) extends Model

抽象类TableModel作为类型参数,在其默认的具体方法之一中使用:

abstract class Table[M <: Model] {
    def parser = SomeExternalBuilder[M]
}

含义相当简单:“根据自己的类,为Table的每个实例提供一个默认的parser。”

问题是SomeExternalBuilder只接受 case class 作为参数(“case classes expected:M”),因此它不会编译。

我可以让Table只将case类作为类型参数吗?

我看到一些答案提供了缺失的copy方法(ref1ref2),所以我尝试了这个:

trait Model[T] {
    def copy: T
}

abstract class Table[M <: Model[M]]

但现在案例类User扩展Model[User]并且必须覆盖copy,每个创建Model的函数都会获取一个类型参数,老实说,代码很快就开始变得残酷,Table中该单行的所有内容。

没有比在每个孩子的身体中复制def parser行更好的方法吗?

修改:N.B。实际功能是来自Play的“anorm”库的def parser: anorm.Macro.namedParser[M]

修改:此宏检查类型的来源:https://github.com/playframework/anorm/blob/0a1b19055ba3e3749044ad8a54a6b2326235f7c8/core/src/main/scala/anorm/Macro.scala#L117

2 个答案:

答案 0 :(得分:1)

  

问题是SomeExternalBuilder只接受一个case类作为参数(&#34; case class expected:M&#34;),所以它不会编译。

我不认为你可以从Scala编译器本身得到这样的消息,这意味着SomeExternalBuilder.apply是一个宏。它需要一个特定的案例类才能知道它的字段,因此如果你可以将M限制为一个案例类(你可以&#39; t):它仍然不接受类型参数。

可以做的是创建一个宏注释,以便在你写的时候。

@HasModel
class SomeTable extends Table[SomeModel] {
  ...
}

自动生成val parser = namedParser[SomeModel]。 或者,也可以写@HasModel[SomeModel] class SomeTable { ... }并生成extends Table[SomeModel]

它不会很难(如宏),但你仍然需要注释每个扩展Table的类。

答案 1 :(得分:0)

不是万无一失的解决方案,但值得一试

案例类扩展了Product和Serialisable。约束Product with Serialisable将帮助您获得某种类型的安全性。 M可以是使用Serialisable扩展Product的任何类。但产品大多是按案例类扩展的

abstract class Table[M <: (Product with Serializable)] { 
  def parser = SomeExternalBuilder[M]
}