我有一个抽象类Model
,我从中创建了案例类:
abstract class Model
case class User(.) extends Model
抽象类Table
将Model
作为类型参数,在其默认的具体方法之一中使用:
abstract class Table[M <: Model] {
def parser = SomeExternalBuilder[M]
}
含义相当简单:“根据自己的类,为Table
的每个实例提供一个默认的parser
。”
问题是SomeExternalBuilder
只接受 case class 作为参数(“case classes expected:M”),因此它不会编译。
我可以让Table
只将case类作为类型参数吗?
我看到一些答案提供了缺失的copy
方法(ref1,ref2),所以我尝试了这个:
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]
。
答案 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]
}