使用Go语言Goldmark添加子节点时出现栈溢出问题求助
解决Goldmark遍历AST注入子列表导致的栈溢出问题
问题根源
你遇到的栈溢出是因为无限递归:每次遍历到ListItem节点时,都会给它添加一个包含新ListItem的子列表。当Walk继续遍历这个新生成的ListItem时,又会触发同样的逻辑,再次添加子列表,循环往复直到栈被撑爆。
解决方案
方案1:跳过当前节点的子节点遍历(简单直接)
如果不需要遍历原ListItem的原有子节点,处理完当前节点后返回ast.WalkSkipChildren,就能避免遍历刚添加的子列表,终止无限循环:
ast.Walk(doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) { if entering { if n.Kind() == ast.KindListItem { subList := ast.NewList(0) subListItem := ast.NewListItem(0) subList.AppendChild(subList, subListItem) leaf := ast.NewString([]byte("Hello")) subListItem.AppendChild(subListItem, leaf) n.AppendChild(n, subList) // 跳过当前节点的子节点遍历,避免处理新增的ListItem return ast.WalkSkipChildren, nil } } return ast.WalkContinue, nil })
方案2:标记已处理节点(保留原有子节点遍历)
如果需要继续遍历原ListItem的原有子节点,可以用一个map记录已处理的节点,遍历的时候跳过标记过的节点:
// 用map记录已经处理过的节点,避免重复操作 processed := make(map[ast.Node]struct{}) ast.Walk(doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) { if entering { if n.Kind() == ast.KindListItem { // 检查是否已经处理过这个节点 if _, ok := processed[n]; ok { return ast.WalkContinue, nil } // 标记当前节点为已处理 processed[n] = struct{}{} subList := ast.NewList(0) subListItem := ast.NewListItem(0) // 标记新增的ListItem,避免后续遍历到它时重复处理 processed[subListItem] = struct{}{} subList.AppendChild(subList, subListItem) leaf := ast.NewString([]byte("Hello")) subListItem.AppendChild(subListItem, leaf) n.AppendChild(n, subList) } } return ast.WalkContinue, nil })
这种方式既可以处理原有的ListItem,又不会因为新增节点触发无限循环,同时还能正常遍历原节点的其他子节点。
内容的提问来源于stack exchange,提问作者sneakyfishies
相关产品推荐
相关产品推荐

