我有一个定义函数的特性 - 我不想指定它将如何工作直到以后。这个特征与几个案例类混合在一起,如下所示:
trait AnItem
trait DataFormatable {
def render():String = "" // dummy implementation
}
case class Person(name:String, age:Int) extends DataFormatable with AnItem
case class Building(numFloors:Int) extends DataFormatable with AnItem
好的,现在我想要包含这种渲染行为的特定实现的可包含模块。试着在这里使用价值类:
object JSON {
implicit class PersonRender( val p:Person ) extends AnyVal {
def render():String = {
//render json
}
}
// others
}
object XML {
implicit class PersonRender( val p:Person ) extends AnyVal {
def render():String = {
//render xml
}
}
// others
}
理想的使用方式如下(假设需要JSON输出):
import JSON._
val p:AnItem = Person("John",24)
println(p.render())
一切都很酷 - 但它不起作用。有没有办法让这个可加载实现的东西工作?我接近了吗?
答案 0 :(得分:0)
DataFormatable
特质在这里什么也没做,只能阻止你。你应该摆脱它。由于您希望根据范围中存在的隐含来替换render
实现,Person
不能拥有自己的render
方法。如果PersonRender
首先没有名为Person
的方法,编译器将只查找到render
的隐式转换。但是因为Person
从render
继承(或被迫实现)DataFormatable
,所以不需要寻找隐式转换。
根据您的修改,如果您有List[AnItem]
的集合,则也无法将元素隐式转换为render
。虽然每个子类可能都有一个隐式转换,它给出了render
,但编译器并不知道它们何时被全部堆积到更抽象类型的列表中。特别是AnItem
。
你怎么能做这个工作?你有两个简单的选择。
其一,如果你想坚持隐式转换,你需要删除DataFormatable
作为你的案例类的超类型,这样他们就没有自己的render
方法。然后,您可以换出XML._
和JSON._
,转换应该有效。但是,您不会被允许混合收藏。
二,完全放弃隐含,让你的特质看起来像这样:
trait DataFormatable {
def toXML: String
def toJSON: String
}
这样,您强制在DataFormatable
中混合的每个类都包含序列化信息(这是应该的方式,而不是将它们隐藏在含义中)。现在,当您拥有List[DataFormatable]
时,您可以证明所有元素都可以转换为JSON或XML,因此您可以转换混合列表。我认为这总体上要好得多,因为代码应该更直接。你有什么进口不应该真正定义下面的行为。想象一下,由于XML._
已导入文件顶部而不是JSON._
,因此可能会出现混淆。