scala upickle / ujson 中对 JSON null 的惯用处理

问题描述 投票:0回答:2

我是 Scala 新手,想学习解决常见问题的惯用方法,例如 Python 的 pythonic。我的问题是使用 upickle 读取 JSON 数据,其中 JSON 值在存在时包含一个字符串,在不存在时包含 null。我想使用自定义值来替换 null。一个简单的例子:

import upickle.default._

val jsonString = """[{"always": "foo", "sometimes": "bar"}, {"always": "baz", "sometimes": null}]"""
val jsonData = ujson.read(jsonString)

for (m <- jsonData.arr) {
  println(m("always").str.length)  // this will work
  println(m("sometimes").str.length)  // this will fail, Exception in thread "main" ujson.Value$InvalidData: Expected ujson.Str (data: null)
}

问题在于字段

"sometimes"
:当为 null 时,我们无法应用
.str
(或映射到除 null 之外的静态类型的任何其他函数)。我正在寻找类似
m("sometimes").str("DEFAULT").length
的东西,其中
"DEFAULT"
是 null 的替代品。

想法1 使用模式匹配,可以进行以下工作:

val sometimes = m("sometimes") match {
  case s: ujson.Str => s.str
  case _ => "DEFAULT"
}
println(sometimes.length)

考虑到 Scala 简洁的语法,这看起来有点复杂,并且在处理多个值时会重复。

想法2 相关问题的答案提到创建一个具有默认值的案例类。对于我的问题,当根据上下文需要不同的替换值时,案例类的创建对我来说似乎不灵活。

想法3 回答另一个问题(不是特定于 upickle) 使用

Try().getOrElse()
进行讨论,即:

import scala.util.Try
// ...
println(Try(m("sometimes").str).getOrElse("DEFAULT").length)

但是,讨论提到为常规程序路径引发异常的成本很高。

解决这个问题的惯用且简洁的方法是什么?

scala ujson upickle
2个回答
1
投票

使用 scala 的 Option 来执行此操作的惯用或 scala 方法。

幸运的是,upickle Values 提供了这些。参考this源代码中的strOpt方法。

您的代码问题是 m("always").str 和 m("sometimes").str 中的 str 方法 使用此代码,您过早地假设所有值都是字符串。这就是 strOpt 方法的由来。如果其值是字符串,则输出字符串;如果不是字符串,则输出 None 类型。我们可以使用 getOrElse 方法来决定如果值为 None 则抛出什么。

以下是处理此问题的最佳方法。

val jsonString = """[{"always": "foo", "sometimes": "bar"}, {"always": "baz", "sometimes": null}]"""

for (m <- jsonData.arr) {
    println(m("always").strOpt.getOrElse("").length)  
    println(m("sometimes").strOpt.getOrElse("").length) 
  } 

输出:

3
3
3
0

这里如果我们得到字符串以外的任何值(null、float、int),代码会将其输出为空字符串。其长度将被计算为0。

基本上,这与您的“Idea1”方法类似,但这是 scala 方式。我抛出一个空字符串而不是“DEFAULT”,因为您不希望空值的长度为 7(字符串“DEFAULT”的长度)。


0
投票

有没有办法知道 jsonData 的大小?

© www.soinside.com 2019 - 2024. All rights reserved.