5.2 递归
函数可以直接或间接调用自身。递归适合处理树形等递归数据结构。
示例:提取 HTML 链接
func visit(links []string, n *html.Node) []string {
if n.Type == html.ElementNode && n.Data == "a" {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit(links, c)
}
return links
}
示例:输出文档结构
func outline(stack []string, n *html.Node) {
if n.Type == html.ElementNode {
stack = append(stack, n.Data)
fmt.Println(stack)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
outline(stack, c)
}
}
只有入栈没有出栈——因为 append 操作的是 slice 拷贝,返回后调用方的 stack 不受影响。
Go 的可变栈
多数语言固定大小调用栈(64KB~2MB),深递归可能栈溢出。Go 使用可变栈,初始很小,按需自动增长,无需担心栈溢出。