盒子
盒子
文章目录
  1. Nim编程早茶
    1. 简单的例子
    2. 编译时执行
    3. marshal 库的限制
    4. 从文件中加载对象

如何使用 marshal 序列化 Nim 对象

Nim编程早茶

这一节我们介绍如何使用标准库 marshal 序列化 Nim 对象。适用于 Nim 1.0.x 系列。

简单的例子

我们可以使用 marshal 序列化 Nim 对象, nowtimes 模块中用来获取当前时刻的函数。

我们使用 $$ 来序列化 Nim 对象,目前 marshal 库使用 json 来序列化,也就是说,Nim 对象会被转换为 json 对象。

我们可以使用 to 宏来从序列化内容中,恢复 Nim 对象。其中 DateTime 是反序列化得到的对象类型。

1
2
3
4
5
6
7
8
9
10
11
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

输出

1
2
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 宏来测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

输出

1
2
3
(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) 并不能识别 Animalnamenum 属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

错误信息:

1
Error: unhandled exception: unknown file(1, 7) Error: unknown field for object of type Cat expected [JsonParsingError]

从文件中加载对象

借助 marshal 模块中的 loadstore 函数,我们可以对 stringStreamfileStream 序列化与反序列化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

输出

1
{"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}