Scala 特征和序列化/反序列化
假设我有两个特点,我想融入一个班级。每个特性都实现了类所需的抽象方法Scala 特征和序列化/反序列化,scala,serialization,traits,Scala,Serialization,Traits,假设我有两个特点,我想融入一个班级。每个特性都实现了类所需的抽象方法 trait Writable { def serialize(out: java.io.DataOutput) } trait T1 extends Writable trait A extends T1 { val aNum: Int abstract override def serialize(out: java.io.DataOutput) = { super.serialize(
trait Writable {
def serialize(out: java.io.DataOutput)
}
trait T1 extends Writable
trait A extends T1 {
val aNum: Int
abstract override def serialize(out: java.io.DataOutput) = {
super.serialize(out)
println("A serialize")
out.writeInt(aNum)
}
def action = println("A action")
}
trait B extends T1 {
val bNum: Int
abstract override def serialize(out: java.io.DataOutput) = {
super.serialize(out)
println("B serialize")
out.writeInt(bNum)
}
def action = println("B action")
}
abstract class M[CT1 <: T1](val mNum: Int) extends Writable {
this: M[CT1] with T1 =>
def serialize(out: java.io.DataOutput) = {
println("M serialize")
out.writeInt(mNum)
}
def action
}
一切正常。但是我如何在尊重混合到M中的特征类型的同时反序列化对象呢?我可以在serialize方法中输出trait的名称,然后在名称上分派M的反序列化方法,但是如果我有M以外的类,A和B可以混合到其中呢?然后,每个类都必须复制M的分派反序列化行为。如果我有多个特性需要混合到一个对象中以使其具体化,并且每个特性都有自己的自定义序列化/反序列化,那么问题会变得更糟。有人处理过这样的问题吗?是的,人们有。方法是使用David MacIver和Debassh Ghosh倡导的类型类模式。德巴西什三部曲
CanBuildFrom
,并将我的TypeClass命名如下:
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]
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)
}
编辑:
你能给我解释一下框架是如何在“带A”和“带B”之间进行选择的吗
使用typeclass模式,库既不混合在A
中,也不混合在B
中。
以scalaxb为例,它在包对象中提供了一个名为scalaxb.fromXML
的方法,定义如下:
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]
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>)
编译器如何知道该做什么?魔法是fromXML
所需的隐式参数,称为隐式格式:XMLFormat[A]
。这要求您在调用scalaxb.fromXML[ipo.Address](…)
的范围内具有XMLFormat[Address]
作为隐式值可用
这在scalaxb生成的代码中可用,因为它将XMLProtocol
混合到ipo
package的package对象中。和ipo.XMLProtocol
定义
implicit lazy val IpoAddressFormat: scalaxb.XMLFormat[ipo.Address] = new DefaultIpoAddressFormat {}
Edit2:
我想我已经开始理解实际问题了。您有一个由trait mixin组成的对象,并且您希望以某种方式“反序列化”其他进程上的trait组合。
正如您所写的,您可以为每个特征包含一些标记,并加载任何可以加载的内容
由于到目前为止我已经写过typeclass模式,让我继续这个方法。将序列化代码放在对象之外的好处是,实际上可以结合对象来描述mixin。假设有特征
trait Foo { def foo: Int }
trait Bar { def bar: Int }
您想将mixin描述为12
。
这是我做的一件事。
我为Foo
、Bar
和Foo with Bar
定义了typeclass实例,并调用
Def.fromXML[Foo with Bar](<obj><foo>1</foo><bar>2</bar></obj>)
我不清楚这些库如何选择在反序列化时混入类的特性。你能解释一下框架是如何选择“带A”还是“带B”的吗?所以trait A和trait B在类M中包含抽象方法的不同实现。我编辑了这个问题以反映这一事实。我希望用traits中定义的行为组合一个对象,并允许对该对象进行序列化和反序列化。换句话说,具体的M实例不仅仅是一个数据类。它有特定的行为。使用反序列化/umarshaling,您需要将实现放在类之外,因为对象还不存在。我已经演示了一种通过使用typeclass来实现这一点的方法,但是如果您愿意,也可以使用companion对象来实现。我认为最好将其描述为声明性依赖项注入,而不是序列化。我正在尝试序列化一个统计模型,以便将其传输到远程节点以并行执行。因此,我需要将其行为指定为序列化协议的一部分。
Right(FooWithBar(1, 2))