Nim编程早茶
这一节我们介绍如何使用标准库 marshal 序列化 Nim 对象。适用于 Nim 1.0.x 系列。
简单的例子
我们可以使用 marshal 序列化 Nim 对象, now 是 times 模块中用来获取当前时刻的函数。
我们使用 $$ 来序列化 Nim 对象,目前 marshal 库使用 json 来序列化,也就是说,Nim 对象会被转换为 json 对象。
我们可以使用 to 宏来从序列化内容中,恢复 Nim 对象。其中 DateTime 是反序列化得到的对象类型。
import times, marshal
let t = now()
echo t
# 序列化
let t_marshal = $$t
echo t_marshal
# 反序列化
let t_unmarshal = to[DateTime](t_marshal)
assert t == t_unmarsha
输出
2019-11-24T20:06:32+08:00
{"nanosecond": 830475600, "second": 32, "minute": 6, "hour": 20, "monthday": 24, "month": "November", "year": 2019, "weekday": "Sunday", "yearday": 327, "isDst": false, "timezone": [1503304, {"zonedTimeFromTimeImpl": {"Field0": 4321957, "Field1": null}, "zonedTimeFromAdjTimeImpl": {"Field0": 4322426, "Field1": null}, "name": "LOCAL"}], "utcOffset": -28800}
编译时执行
其中 $$ 和 to 都是可以在编译期执行的。我们可以使用 static 宏来测试。
import times, marshal
type
Animal = object of RootObj
name: string
birthday: DateTime
num: int
static:
let t = Animal(name: "animal", num: 12, birthday: now())
echo t
# 序列化
let t_marshal = $$t
echo t_marshal
# 反序列化
let t_unmarshal = to[Animal](t_marshal)
echo t_unmarshal
输出
(name: "animal", birthday: 2019-11-25T09:41:41+08:00, num: 12)
{"name": "animal", "birthday": {"nanosecond": 735557600, "second": 41, "minute": 41, "hour": 9, "monthday": 25, "month": "November", "year": 2019, "weekday": "Monday", "yearday": 328, "isDst": false, "timezone": [6881352, {"zonedTimeFromTimeImpl": {"Field0": 4325685, "Field1": null}, "zonedTimeFromAdjTimeImpl": {"Field0": 4326154, "Field1": null}, "name": "LOCAL"}], "utcOffset": -28800}, "num": 12}
(name: "animal", birthday: 2019-11-25T09:41:41+08:00, num: 12)
marshal 库的限制
要注意,marshal 模块中的序列化,并没有序列化对象的类型。如果对象使用了运行时类型,就会出现错误。
Cat 继承 Animal 类型,但编译时,并不能获得这种继承关系,所以说,to[Cat](t_marshal) 并不能识别 Animal 的 name 和 num 属性。
type
Animal = object of RootObj
name: string
num: int
Wolf = object of Animal
bark: bool
Cat = object of Animal
bark: bool
Dog = object
name: string
num: int
bark: bool
static:
let t = Cat(name: "animal", num: 12)
echo t
# 序列化
let t_marshal = $$t
echo t_marshal
# 反序列化
let t_unmarshal = to[Cat](t_marshal)
echo t_unmarshal
错误信息:
Error: unhandled exception: unknown file(1, 7) Error: unknown field for object of type Cat expected [JsonParsingError]
从文件中加载对象
借助 marshal 模块中的 load 与 store 函数,我们可以对 stringStream 与 fileStream 序列化与反序列化。
import marshal, streams
# 从 stringStream 加载 array 对象
var s0 = newStringStream("[1, 2, 3]")
var a0: array[3, int]
load(s0, a0)
let t = now()
var s1 = newStringStream("")
# 序列化
let t_marshal = $$t
# 存储序列化对象
store(s1, t_marshal)
# 反序列化
let t_unmarshal = to[DateTime](t_marshal)
assert t == t_unmarshal
# 文件中读取
# s1.setPosition(0)
# echo s1.readAll
echo t_marshal
输出
{"nanosecond": 237341300, "second": 44, "minute": 27, "hour": 20, "monthday": 24, "month": "November", "year": 2019, "weekday": "Sunday", "yearday": 327, "isDst": false, "timezone": [1531976, {"zonedTimeFromTimeImpl": {"Field0": 4321957, "Field1": null}, "zonedTimeFromAdjTimeImpl": {"Field0": 4322426, "Field1": null}, "name": "LOCAL"}], "utcOffset": -28800}