推荐用 json.Encoder 逐个编码链表节点,需节点字段可导出且支持 JSON 编码,显式忽略 Next 指针防循环引用;gob 虽可编码指针但跨语言不兼容且不自动展开链表;禁用 fmt.Fprintln 拼接;写入前须检测环。

用 json.Encoder 写入链表节点(推荐)
Go 标准库不提供内置链表序列化支持,但只要链表节点可导出、结构清晰,json.Encoder 是最稳妥的按序写入方式。它逐个编码节点,不占用额外内存,天然保持插入/遍历顺序。
关键前提是:链表节点字段必须首字母大写(可导出),且类型支持 JSON 编码(如 int、string、[]byte 等)。
- 定义节点结构时避免匿名字段或不可导出字段(如
next *Node不会写入 JSON,这是预期行为) - 打开文件用
os.Create或os.OpenFile,传给json.NewEncoder - 遍历链表,对每个节点调用
enc.Encode(node)—— 每次写入一行 JSON 对象,自然保序
type ListNode struct {
Val int `json:"val"`
Next *ListNode `json:"-"` // 显式忽略指针,防止循环引用
}
// 遍历时只传 node.Val 相关数据,不传 Next
for p := head; p != nil; p = p.Next {
if err := enc.Encode(p); err != nil {
log.Fatal(err)
}
}
用 gob.Encoder 写入需注意兼容性
gob 能直接编码结构体甚至含指针的值,但它是 Go 专属二进制格式,跨语言不可读,且版本升级可能破坏解码兼容性。
更关键的是:gob 不自动“展开”链表 —— 如果你直接 enc.Encode(head),它只会编码头节点本身(Next 字段被序列化为 nil 或地址值,无法还原链式结构)。
立即学习“go语言免费学习笔记(深入)”;
- 必须手动遍历,逐个
Encode节点值(同 JSON 方式),不能直接 encode 整个链表变量 - 若节点含非
gob支持类型(如func、不导出字段、未注册的自定义类型),会 panic - 写入前建议先调用
enc.Encode(len(list))写入长度,便于后续读取时预分配
避免用 fmt.Fprintln 拼接字符串写入
看似简单,但极易出错:字段顺序依赖 fmt 格式字符串,缺失字段易遗漏;无类型信息,读取时需硬解析;空格/换行不一致会导致解析失败;不支持嵌套结构。
- 例如
fmt.Fprintln(w, node.Val, node.Name)—— 若Name含空格,读取时用strings.Fields会切错 - 没有转义机制,
Val为负数或浮点数时格式难统一(如-0.0vs0) - 无法表达 nil、布尔、时间等类型,后期扩展成本高
写入前必须检查链表是否带环
所有遍历写入方式都隐含一个前提:链表是**有向无环图(DAG)**。如果链表存在环(比如误将尾节点 Next 指向前面某节点),遍历会无限循环,程序卡死或触发栈溢出。
- 生产代码中,若链表来源不可信(如用户输入构造),务必先用快慢指针检测环:
hasCycle(head) - 即使只是调试,也建议在写入循环里加计数上限(如
for i := 0; i ),防意外 - 日志中记录实际写入节点数,与预期长度比对,是快速发现环或截断的手段


















