json - 我应该如何在Scala中指定类似JSON的非结构化数据的类型?

标签 json generics data-structures scala strong-typing

我正在考虑将一个非常简单的文本模板库移植到scala,主要是作为学习该语言的练习。该库目前同时在Python和Javascript中实现,其基本操作或多或少可以归结为以下内容(在python中):

template = CompiledTemplate('Text {spam} blah {eggs[1]}')
data = { 'spam': 1, 'eggs': [ 'first', 'second', { 'key': 'value' }, true ] }
output = template.render(data)

在Scala中,这都不是很难做到的,但是我不清楚的是如何最好地表达data参数的静态类型。

基本上,此参数应该能够包含您在JSON中发现的各种东西:一些原语(字符串,整数, bool 值,空值)或零个或多个项目的列表,或零个或多个项目的映射。 (出于这个问题的目的,可以将 map 限制为具有字符串键,这似乎是Scala始终喜欢事物的方式。)

我最初的想法只是将Map[string, Any]用作顶级对象,但这对我来说似乎并不完全正确。实际上,我不想在其中添加任何类的任意对象。我只需要上面概述的元素。同时,我认为在Java中我真正能够获得的最接近的应该是Map<String, ?>,而且我知道Scala的一位作者设计了Java的泛型。

我特别好奇的一件事是,具有类似类型系统的其他功能语言如何处理此类问题。我有一种感觉,我真正想在这里提出的是一组可以进行模式匹配的案例类,但是我无法完全想象它的外观。

我在Scala中进行了编程,但是老实说,我的眼睛开始对协方差/协方差东西感到有些呆滞,我希望有人可以向我更清楚和简洁地说明这一点。

最佳答案

您发现需要某种案例类来对数据类型进行建模。在函数式语言中,这些类型的事情称为“抽象数据类型”,您可以通过谷歌搜索一点来了解有关Haskell如何使用它们的全部信息。 Scala相当于Haskell的ADT使用密封的特征和案例类。

让我们看一下Scala标准库或《 Scala编程》一书中的rewrite of the JSON parser combinator。它使用抽象数据类型JsValue来表示JSON值,而不是使用Map [String,Any]表示JSON对象,而不是使用Any来表示任意JSON值。 JsValue有几种子类型,表示可能的JSON值类型:JsStringJsNumberJsObjectJsArrayJsBoolean(JsTrueJsFalse)和JsNull

处理这种形式的JSON数据涉及模式匹配。由于JsValue是密封的,因此如果您未处理完所有情况,编译器都会警告您。例如,toJson的代码(该方法采用JsValue并返回该值的String表示形式)如下所示:

  def toJson(x: JsValue): String = x match {
    case JsNull => "null"
    case JsBoolean(b) => b.toString
    case JsString(s) => "\"" + s + "\""
    case JsNumber(n) => n.toString
    case JsArray(xs) => xs.map(toJson).mkString("[",", ","]")
    case JsObject(m) => m.map{case (key, value) => toJson(key) + " : " + toJson(value)}.mkString("{",", ","}")
  }

模式匹配不仅可以确保我们处理每种情况,还可以从其JsType中“解包”基础值。它提供了一种类型安全的方式来知道我们已经处理了每种情况。

此外,如果您在编译时知道要处理的JSON数据的结构,则可以执行n8han's extractors之类的非常酷的事情。非常强大的功能,请查看。

关于json - 我应该如何在Scala中指定类似JSON的非结构化数据的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/728871/

相关文章:

php - 在 Yii 1.x 中编码未转义的 JSON

javascript - jquery自动完成从本地文件获取数据

java - Hamcrest 匹配器中的泛型

delphi - TStringList 与 TList<string>

c++ - Map结构也支持排序?

arrays - 查找总和与给定值的距离最小的对/三元组

python - python中UDP服务器解析JSON对象的数据结构

python - 需要身份验证 - 使用 Python 建立 AIM OSCAR session 时出现问题

c# - 绑定(bind)到数据库的自定义通用 IEnumerator

寻找长度为 k 的第一个重复子串的算法