Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 特征和序列化/反序列化_Scala_Serialization_Traits - Fatal编程技术网

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倡导的类型类模式。德巴西什三部曲

对所有中级Scala程序员特别有用

今天,包括我在内的许多图书馆都采用了这种方法。看

我借用了Scala Collections的命名思想,
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))