Scala酸洗:如何



我正在尝试使用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"类型信息才能正确地取消拾取。

相关内容

  • 没有找到相关文章