我正在尝试使用Scala的"pickle"序列化,我看到了演示它的相同示例:
import scala.pickling._
import json._
val pckl = List(1, 2, 3, 4).pickle
脱模和酸洗一样容易:
val lst = pckl.unpickle[List[Int]]
这个例子提出了一些问题。首先,它跳过了从对象到字符串的转换。显然,您需要调用pckl.value来获得json字符串表示。
解开更令人困惑。反序列化是将字符串(或字节)转换为对象的行为。如果没有对象的字符串/二进制表示,这个"示例"为什么演示反序列化?
那么,如何使用pickle库反序列化简单的对象呢?
使用类型系统和案例类来实现您的目标。您可以取消拾取到层次结构中的某个上级类型(最多包括AnyRef)。这里有一个例子:
trait Zero
case class One(a:Int) extends Zero
case class Two(s:String) extends Zero
object Test extends App {
import scala.pickling._
import json._
// String that can be sent down a wire
val wire: String = Two("abc").pickle.value
// On the other side, just use a case class
wire.unpickle[Zero] match {
case One(a) => println(a)
case Two(s) => println(s)
case unknown => println(unknown.getClass.getCanonicalName)
}
}
好吧,我想我明白了。
import scala.pickling._
import json._
var str = Array(1,2,3).pickle.value // this is JSON string
println(str)
val x = str.unpickle[Array[Int]] // unpickle from string
将生成JSON字符串:
{
"tpe": "scala.Array[scala.Int]",
"value": [
1,
2,
3
]
}
所以,就像我们pickle任何类型一样,我们可以取消pickle字符串。序列化类型由"json."中声明的隐式格式化程序控制,可以用"binary."
看起来您将从一个pickle开始,将其解锁到一个case类。但是可以将JSON字符串提供给JSONPickle类以获得起始pickle。
下面是一个基于数组json测试的例子
package so
import scala.pickling._
import json._
case class C(arr: Array[Int]) { override def toString = s"""C(${arr.mkString("[", ",", "]")})""" }
object PickleTester extends App {
val json = """{"arr":[ 1, 2, 3 ]}"""
val cPickle = JSONPickle( json )
val unpickledC: C = cPickle.unpickle[C]
println( s"$unpickledC, arr.sum = ${unpickledC.arr.sum}" )
}
打印的输出为:
C([1,2,3]), arr.sum = 6
我可以从测试中删除"tpe",也可以在测试的输入JSON上删除.stripMargin.trim
。它在一条线上起作用,但我认为它可能更明显地是分开的。我不清楚测试中的"tpe"是否应该为传入的JSON提供类型安全性度量。
看起来他们唯一支持酸洗的其他类是BinaryPickle,除非你想自己滚。最新的scala-pickle快照jar需要准引号来编译这个答案中的代码。
今天早上,我尝试了一些更复杂的方法,发现传入JSON中的非主键需要"tpe",这表明序列化字符串必须与pickler兼容(我将其混合到上面的代码中):
case class J(a: Option[Boolean], b: Option[String], c: Option[Int]) { override def toString = s"J($a, $b, $c)" }
...
val jJson = """{"a": {"tpe": "scala.None.type"},
| "b":{"tpe": "scala.Some[java.lang.String]","x":"donut"},
| "c":{"tpe": "scala.Some[scala.Int]","x":47}}"""
val jPickle = JSONPickle( jJson.stripMargin.trim )
val unpickledJ: J = jPickle.unpickle[J]
println( s"$unpickledJ" )
...
从本质上讲,我必须在J(None, Some("donut"), Some(47))
上使用.value
来找出如何创建jJson
输入值,以防止取消拾取引发异常。
J
的输出如下:
J(None, Some(donut), Some(47))
从这个测试中可以看出,如果传入的JSON都是JSONPickle魔术所使用的主类或事例类(或组合),但其他一些类(如Options)需要额外的"tpe"类型信息才能正确地取消拾取。