跳到主要内容
版本:0.17

引用

默认情况下,Fory 会把每个值都当作独立副本处理。如果同一个对象出现在两个字段中,它会被序列化两次;反序列化后,你得到的也是两个彼此独立的副本。以下情况应启用引用跟踪:

  • 同一个对象实例会在对象图中的多个位置被引用
  • 数据中包含循环结构,例如一个节点指向自己
  • 往返之后必须保留对象身份

对于普通的树状数据,应保持引用跟踪关闭,因为它会引入少量额外开销。

第一步:在 Fory 实例上启用引用跟踪

const fory = new Fory({ ref: true });

第二步:标记可能出现共享引用或循环引用的字段

对于每个值可能被共享或形成循环的字段,都需要在字段 schema 上调用 .setTrackingRef(true)

const nodeType = Type.struct("example.node", {
value: Type.string(),
next: Type.struct("example.node").setNullable(true).setTrackingRef(true),
});

全局开关和字段级开关必须同时启用。缺少任何一个,值都会被复制,而不是按引用恢复。

循环自引用示例

import Fory, { Type } from "@apache-fory/core";

const nodeType = Type.struct("example.node", {
name: Type.string(),
selfRef: Type.struct("example.node").setNullable(true).setTrackingRef(true),
});

const fory = new Fory({ ref: true });
const { serialize, deserialize } = fory.register(nodeType);

const node: any = { name: "root", selfRef: null };
node.selfRef = node;

const copy = deserialize(serialize(node));
console.log(copy.selfRef === copy); // true

共享嵌套引用示例

const innerType = Type.struct(501, {
value: Type.string(),
});

const outerType = Type.struct(502, {
left: Type.struct(501).setNullable(true).setTrackingRef(true),
right: Type.struct(501).setNullable(true).setTrackingRef(true),
});

const fory = new Fory({ ref: true });
const { serialize, deserialize } = fory.register(outerType);

const shared = { value: "same-object" };
const copy = deserialize(serialize({ left: shared, right: shared }));
console.log(copy.left === copy.right); // true

何时启用

以下情况建议启用引用跟踪:

  • 同一个对象实例会被多个字段重复引用
  • 你的对象图可能存在环
  • 反序列化后对象身份是否保持一致很重要

以下情况建议关闭:

  • 数据是普通树结构
  • 你希望获得最低开销
  • 对象身份并不重要

跨语言说明

引用跟踪是 Fory 二进制协议的一部分,并且可以跨运行时工作。为了让行为一致,两端都必须启用引用跟踪,并把相同字段标记为引用跟踪字段。

相关主题