如何将Go语言中的双遍历循环替换为两次手动调用(疑难)
手动替换HTML节点遍历循环的问题分析与解决
我来帮你拆解下这两种尝试的问题,以及怎么正确手动模拟原循环的逻辑:
首先明确你原循环的核心作用:它在遍历当前节点n的全部子节点——从FirstChild开始,顺着NextSibling这条链表一直走到nil,所以能完整输出所有子节点及嵌套内容:html head body a 1 a 1 div a 2 a 3
第一种尝试的问题
你写的这段代码:
if n.FirstChild != nil { indent(space+" ", n.FirstChild) } if n.FirstChild != nil && n.FirstChild.NextSibling != nil { indent(space+" ", n.FirstChild.NextSibling) }
只处理了n的前两个子节点,但子节点的链表可能更长(比如后面还有div节点),你没有继续沿着NextSibling往下遍历剩余的子节点,自然只能输出一半内容。
第二种尝试的问题
第二种写法犯了节点类型混淆的错误:
if n.FirstChild != nil { indent(space+" ", n.FirstChild) } if n.NextSibling != nil { indent(space+" ", n.NextSibling) }
这里的n.NextSibling是当前节点n自己的兄弟节点,而不是n的子节点的兄弟节点!虽然碰巧输出了所有内容,但这些节点被错误地当成n的子节点来处理,缩进层级完全不符合预期,所以会出现缩进异常。
正确的手动调用方式
如果一定要手动模拟循环,必须严格沿着子节点的NextSibling链条逐个访问,比如:
// 先获取第一个子节点 currentChild := n.FirstChild if currentChild != nil { indent(space+" ", currentChild) // 移动到下一个子节点 currentChild = currentChild.NextSibling if currentChild != nil { indent(space+" ", currentChild) // 继续移动到下一个,直到currentChild为nil currentChild = currentChild.NextSibling if currentChild != nil { indent(space+" ", currentChild) // ... 重复这个逻辑直到所有子节点都处理完 } } }
不过这种写法非常死板,一旦子节点数量变化就会失效,所以如果子节点数量不确定,原循环的写法才是最优解。核心要记住:遍历子节点必须沿着FirstChild -> NextSibling -> ... -> nil这条链表走,不能跳去其他节点链。
内容的提问来源于stack exchange,提问作者ABSimon
相关产品推荐
相关产品推荐

