特征和序列化/反序列化

2023-12-27

假设我有两个特征想混合到一个班级中。每个特征都实现类需要的抽象方法。

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
}

然后我可以用 A 或 B 构造一个具体的 M 并序列化:

scala> val m1 = new M[A](10) with A { val aNum = 20 }
m1: M[A] with A = $anon$1@67c1e630

scala> val m2 = new M[B](20) with B { val bNum = 30 }
m2: M[B] with B = $anon$1@c36f58e

scala> val out = new java.io.DataOutputStream(new java.io.ByteArrayOutputStream())
out: java.io.DataOutputStream = java.io.DataOutputStream@87afebf

scala> m1.serialize(out)
M serialize
A serialize

scala> m2.serialize(out)
M serialize
B serialize

一切都按预期进行。但是如何反序列化对象,同时尊重混合到 M 中的特征类型?我可以在序列化方法中输出特征的名称,然后在名称上分派 M 的反序列化方法,但是如果我有除 M 之外的可以混合 A 和 B 的类怎么办?然后,每个类都必须重复 M 的调度反序列化的行为。如果我有多个特征需要混合到一个对象中以使其具体化,并且每个特征都有自己的自定义序列化/反序列化,那么问题会变得更糟。有人解决这样的问题吗?


是的,人们有。正确的方法是使用 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))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

特征和序列化/反序列化 的相关文章

随机推荐

  • redshift - 如何插入表生成的时间序列

    我正在尝试在 Redshift 中生成时间序列并插入表中 但没有成功 到目前为止我已经尝试过 insert into date dateid date SELECT to char datum YYYYMMDD int AS dateid
  • 有没有办法判断是否显示软键盘?

    有没有办法判断软键盘是否显示在活动中 I tried InputMethodManager manager InputMethodManager getSystemService getApplicationContext INPUT ME
  • Android Camera2 API - 检测我们何时获得焦点

    因此 我设法用旧相机按照我想要的方式创建了我想要的功能 使用 mCamera autoFocus autoFocusCallback 我检测何时获得焦点并在预览模式下运行所需的代码 现在我很难掌握如何在camera2 API 中执行相同的操
  • 完整的日历适合容器并隐藏滚动

    我无法弄清楚如何缩放 fullcalendar 以适应它的父容器 我想在单个页面上为用户显示周视图 而无需滚动 因此他们可以快速查看一周的项目 如果我需要使文本变小 插槽高度变小等 我没问题 但我只是不确定如何根据浏览器窗口的大小动态地执行
  • 在 C# 中使用“out”关键字返回多个值

    我目前正在努力理解它的含义 当它说使用 out 关键字我们能够return多个值 例如 来自 msdn 站点 https msdn microsoft com en us library ee332485 aspx https msdn m
  • Python 中的通用命令模式和命令调度模式

    我正在寻找一个CommandPython 中的模式实现 根据维基百科 http en wikipedia org wiki Command pattern 命令模式是一种设计 对象用于的模式 代表并封装所有 调用方法所需的信息 稍后 我唯一
  • JS 对象文字和 JSON 字符串有什么区别?

    我对人们所说的对象文字 JSON JavaScript 对象的确切含义感到困惑 对我来说 它们看起来很相似 foo bar bar baz AFAIK 上面是对象文字 json 以及 javascript 对象 不是吗 对象字面量和 jso
  • 如何确保打印偶数奇数的两个线程在此实现中保持先偶后奇的顺序?

    我创建了两个可运行的作业 PrintEvenNumbersJob 和 PrintOddNumbersJob 并生成了两个线程来执行这些作业 这似乎工作得很好 但我对这个实施感到有些可疑 我可以对这个实施有一些意见和建议吗 我在这个实现中看到
  • Python 是强类型的吗?

    我遇到过一些链接 说 Python 是一种强类型语言 但是 我认为在强类型语言中你不能这样做 bob 1 bob bob 我认为强类型语言不接受运行时的类型更改 也许我对强 弱类型的定义错误 或过于简单 那么 Python 是强类型语言还是
  • jQuery 在 AJAX 请求时同时发送 GET 和 POST 参数

    如何使用 jQuery AJAX 请求同时发送 GET 和 POST 参数 我正在尝试添加do ajax id ID to url 但结果请求仅打磨至sss php没有查询字符串 获取部分 谢谢 ajax url sss php do aj
  • 如何在 WIQL 工作项中获取层次结构

    我在 TFS 中有一个像这样的层次结构 其中 1 个功能可以有 N 个产品待办事项列表项目 而单个产品产品待办列表项目可以有 N 个任务 错误 树结构 特点1 gt PB1 gt 任务1 任务2 任务3 my Query string qu
  • 制作 Ubuntu 可执行文件

    我使用 gcc 编译器编写了一个 C 程序 现在它没有 GUI 组件 我正在使用 makefile 编译它并在终端中运行它 我需要部署它 以便可执行文件是独立的 我希望可执行文件有一个图标 单击时在终端中启动程序 谁能告诉我该怎么做 基础
  • SonarQube 中的质量门故障不会导致 Teamcity 中的构建失败

    我在 TeamCity 中建立了一个 Build 项目 并将 Sonarqube 与其集成 该项目正在构建 甚至在 SonarQube 控制台中成功发布报告 但当质量门失败时 它并不会破坏构建 我搜索并阅读了有关构建断路器的信息 但它已经受
  • 如何根据浏览器宽度动态调整CSS样式表?

    我们正在开发一款开源网络应用程序 供世界各地的艺术教师一起工作 我们需要一个漂亮的网站 它可以根据浏览器的活动宽度进行自我调整 就像 google org 或 barackobama com 做得很好一样 我们可以检测浏览器 操作系统等 但
  • 将请求记录到 django-rest-framework

    出于调试目的 我想使用 Django 的日志机制来记录每个传入请求 到达 django rest framework 的门口时的情况 Django 通过以下方式提供其请求的日志记录 仅 警告 日志级别及以上 来自 settings py 中
  • Apache 错误:无法加载 mod_access_compat.so

    我正在尝试运行 PHP 应用程序 但在尝试设置 Apache 2 4 时不断收到错误 错误是 httpd C Apache24 Apache24 conf httpd conf 第 72 行存在语法错误无法将 module mod acce
  • GitFlow:发布分支和主分支有什么区别?

    我刚刚看了一眼这个 gitflow 备忘单 http danielkummer github io git flow cheatsheet 我不明白release branch 谁能告诉我两者之间的区别release and master分
  • 在 AngularJS 中对对象数组进行分组

    基于如下所示的数组 var members name john team 1 name kevin team 1 name rob team 2 name matt team 2 name clint team 3 name will te
  • 如何获得 Firebase 节点的随机子节点?

    首先 这是我的数据库结构 我的目标是从 DE 节点获取一个随机问题对象以便稍后显示它 并且由于没有查询随机子项的内置支持 我必须自己从该迭代器以某种方式获取一个随机对象 目前 我有这段代码 但对如何将其串在一起感到困惑 DatabaseRe
  • 特征和序列化/反序列化

    假设我有两个特征想混合到一个班级中 每个特征都实现类需要的抽象方法 trait Writable def serialize out java io DataOutput trait T1 extends Writable trait A