递归地将字符串附加到切片会导致 golang 中出现内存不足错误
appending strings to a slice recursively causes out of memory error in golang
我正在尝试解析 HTML 页面并打印其链接。
我将遍历已解析的 Html 树,递归地向一段字符串添加链接。
当我收到 内存不足错误
时,我遗漏了一些东西
这是我的代码:
package parser
import (
"errors"
"io"
"golang.org/x/net/html"
)
//URLParser returns all the urls inside a html page
type URLParser struct {
}
//GetURLS returns all
func (URLParser) GetURLS(htmlInput io.Reader) (*[]string, error) {
result := []string{}
htmlRoot, err := html.Parse(htmlInput)
//result := make([]string, 1000)
if err != nil {
parserError := errors.New("html parser failed with error" + err.Error())
return nil, parserError
}
finalResult := traverseHTMLTree(htmlRoot, &result)
return finalResult, nil
}
func traverseHTMLTree(node *html.Node, result *[]string) *[]string {
if node == nil {
return nil
}
if isLinkElement(node) {
currlink, shouldUse := getURLAttrb(node.Attr)
if shouldUse {
*result = append(*result, currlink)
}
}
for currNode := node.FirstChild; currNode != nil; currNode = currNode.NextSibling {
currRest := traverseHTMLTree(currNode, result)
if currRest != nil {
*result = append(*currRest, *result...)
}
}
return result
}
func getURLAttrb(attr []html.Attribute) (string, bool) {
for i := 0; i < len(attr); i++ {
if attr[i].Key == "href" {
return attr[i].Val, true
}
}
return "", false
}
func isLinkElement(node *html.Node) bool {
if node.Type == html.ElementNode {
if node.Data == "a" {
return true
}
}
return false
}
当我只是尝试将链接打印到 stdout 时,它工作得很好,所以它必须与我处理切片的方式有关..
对于 HTML 树中的每个节点,您递归地将结果数组的内容添加到自身。那应该会增长得很快。
请注意,当您检查是否 isLinkElement
时,您将项目添加到结果列表中。
然后对于 html 树的每个元素,将结果数组的内容附加到自身,使其加倍。
您正在传递一个指向切片的指针。您有效地为整个程序使用了一个切片,并不断添加到它。您从遍历 HTML 树中 return 得到的是同一个切片,而不是它的副本。所以它一直在增长。
一种解决方法是:不要将指针传递给切片。传递当前切片,更新它,return 新切片。
我正在尝试解析 HTML 页面并打印其链接。 我将遍历已解析的 Html 树,递归地向一段字符串添加链接。 当我收到 内存不足错误
时,我遗漏了一些东西这是我的代码:
package parser
import (
"errors"
"io"
"golang.org/x/net/html"
)
//URLParser returns all the urls inside a html page
type URLParser struct {
}
//GetURLS returns all
func (URLParser) GetURLS(htmlInput io.Reader) (*[]string, error) {
result := []string{}
htmlRoot, err := html.Parse(htmlInput)
//result := make([]string, 1000)
if err != nil {
parserError := errors.New("html parser failed with error" + err.Error())
return nil, parserError
}
finalResult := traverseHTMLTree(htmlRoot, &result)
return finalResult, nil
}
func traverseHTMLTree(node *html.Node, result *[]string) *[]string {
if node == nil {
return nil
}
if isLinkElement(node) {
currlink, shouldUse := getURLAttrb(node.Attr)
if shouldUse {
*result = append(*result, currlink)
}
}
for currNode := node.FirstChild; currNode != nil; currNode = currNode.NextSibling {
currRest := traverseHTMLTree(currNode, result)
if currRest != nil {
*result = append(*currRest, *result...)
}
}
return result
}
func getURLAttrb(attr []html.Attribute) (string, bool) {
for i := 0; i < len(attr); i++ {
if attr[i].Key == "href" {
return attr[i].Val, true
}
}
return "", false
}
func isLinkElement(node *html.Node) bool {
if node.Type == html.ElementNode {
if node.Data == "a" {
return true
}
}
return false
}
当我只是尝试将链接打印到 stdout 时,它工作得很好,所以它必须与我处理切片的方式有关..
对于 HTML 树中的每个节点,您递归地将结果数组的内容添加到自身。那应该会增长得很快。
请注意,当您检查是否 isLinkElement
时,您将项目添加到结果列表中。
然后对于 html 树的每个元素,将结果数组的内容附加到自身,使其加倍。
您正在传递一个指向切片的指针。您有效地为整个程序使用了一个切片,并不断添加到它。您从遍历 HTML 树中 return 得到的是同一个切片,而不是它的副本。所以它一直在增长。
一种解决方法是:不要将指针传递给切片。传递当前切片,更新它,return 新切片。