2015-02-12 57 views
0

我有一个特征定义了一个函数 - 我不想指定它将如何工作,直到以后。这个特点是混在几个班的情况下,像这样:在scala中使用值类来实现特征方法?

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

DataFormatable特质在这里什么也没有做,只是让你回不去。你应该摆脱它。由于您想根据范围内存在的隐含实现render实现,因此Person不能有有自己的render方法。如果Person首先没有名为render的方法,编译器将仅查找隐式转换为PersonRender。但是因为PersonDataFormatable继承(或被迫执行)render,所以不需要寻找隐式转换。

根据您的编辑,如果您有一个List[AnItem]的集合,也不可能将元素隐式转换为具有render。虽然每个子类都可能有一个隐式转换,但它们会给予它们render,编译器不知道它们何时全部堆积到更抽象类型的列表中。特别是一个空的特质,如AnItem

您如何完成这项工作?你有两个简单的选项。

一,如果你想坚持隐式转换,你需要删除DataFormatable作为你的案例类的超类型,以便它们没有自己的render方法。然后你可以换出XML._JSON._,转换应该可以工作。但是,你不会被允许混合收藏。

二,完全放弃了implicits,有你的特点是这样的:

trait DataFormatable { 
    def toXML: String 
    def toJSON: String 
} 

这样,你强迫每一个在DataFormatable混合包含序列化信息(这是它应该是这样的类,而比隐藏它们隐含)。现在,当您有List[DataFormatable]时,您可以证明所有元素都可以转换为JSON或XML,因此您可以转换混合列表。我认为这会更好,因为代码应该更直接。你有什么进口产品不应该确定后续行为。想象一下可能会出现的混淆,因为XML._已被导入到文件的顶部而不是JSON._

+0

我想我明白了。所以我更新了我的例子。如果我有一组具有不同实现的对象(特征)(比如上面的AnItem列表),我想将它们呈现为JSON或XML,具体取决于。如果它们中没有一个实现render(),那么在修改的示例中对特征(AnItem)进行操作时,编译器如何找到render()? – Greg 2015-02-12 03:51:05

+0

它不能基于'AnItem'的类型信息。要么编译器需要知道你有'Person',所以它可以找到正确的隐式,或者'Person'(和其他类型)可能应该从一个共同的特性实现诸如toJSON和toXML等方法。这取决于你想要走哪条路。 – 2015-02-12 04:01:24

+0

@Greg看我的编辑。 – 2015-02-12 11:59:10

相关问题