是的,人们有。正确的方法是使用 David MacIver 倡导的类型类模式sbinary http://code.google.com/p/sbinary/和德巴什·戈什的sjson https://github.com/debasishg/sjson。德巴什的三部曲
- Scala 隐式:类型类我来了 http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html
- 重构为 Scala 类型类 http://debasishg.blogspot.com/2010/07/refactoring-into-scala-type-classes.html
- sjson:现在在 Scala 中提供基于类型类的 JSON 序列化 http://debasishg.blogspot.com/2010/07/sjson-now-offers-type-class-based-json.html
对于所有中级 Scala 程序员特别有用。
如今,许多图书馆都在采用这种方法,包括我的图书馆scalaxb http://scalaxb.org/. See
- 基于类型类的 XML 数据绑定 http://scalaxb.org/typeclass
我借用了 Scala Collections 的命名理念CanBuildFrom
并将我的类型类命名如下:
trait CanReadXML[A] {
def reads(seq: scala.xml.NodeSeq): Either[String, A]
}
trait CanWriteXML[A] {
def writes(obj: A, namespace: Option[String], elementLabel: Option[String],
scope: NamespaceBinding, typeAttribute: Boolean): NodeSeq
}
trait XMLFormat[A] extends CanWriteXML[A] with CanReadXML[A]
Edit:
你能向我解释一下框架如何在“with A”或“with B”之间进行选择吗?
使用类型类模式,这些库既不混合也不混合A
nor B
。
以scalaxb为例,它提供了一个名为scalaxb.fromXML
在包对象中定义如下:
def fromXML[A](seq: NodeSeq, stack: List[ElemName] = Nil)
(implicit format: XMLFormat[A]): A = format.reads(seq, stack) match {
case Right(a) => a
case Left(a) => throw new ParserFailure(a)
}
假设您有 XML 文档,并且您希望将其解组(反序列化)为ipo.Address
对象,你会调用
scalaxb.fromXML[ipo.Address](<shipTo xmlns="http://www.example.com/IPO">
<name>Foo</name>
<street>1537 Paper Street</street>
<city>Wilmington</city>
</shipTo>)
The Address
对象使用类型类模式保持纯粹:
case class Address(name: String, street: String, city: String)
编译器如何知道要做什么?神奇的是所需的隐式参数fromXML
called implicit format: XMLFormat[A]
。这需要你有XMLFormat[Address]
可用作范围内的隐式值,其中scalaxb.fromXML[ipo.Address](...)
叫做。
这在 scalaxb 生成的代码中可用,因为它混合了XMLProtocol
进入包对象ipo
包裹。和ipo.XMLProtocol
定义
implicit lazy val IpoAddressFormat: scalaxb.XMLFormat[ipo.Address] = new DefaultIpoAddressFormat {}
Edit2:
我想我开始理解真正的问题了。您有一个由特征混合组成的对象,并且您希望以某种方式“反序列化”其他进程上的特征组合。
正如您所写,您可以为每个特征添加一些标签,并加载任何可以加载的内容。
由于到目前为止我已经写了关于类型类模式的文章,所以让我继续该方法。拥有序列化代码的好处outside对象的特点是你实际上可以描述对象的 mixin 组合。假设有特征
trait Foo { def foo: Int }
trait Bar { def bar: Int }
你想将 mixin 描述为<obj><foo>1</foo><bar>2</bar></obj>
。
这是一个gist https://gist.github.com/1121835我振作起来。
我定义了类型类实例Foo
, Bar
, and Foo with Bar
,并称
Def.fromXML[Foo with Bar](<obj><foo>1</foo><bar>2</bar></obj>)
返回的
Right(FooWithBar(1, 2))