doujia1939 2016-02-16 18:44
浏览 92
已采纳

golang-切片中指针的内容在递归函数运行期间发生更改

func getAllCertainDivs(className string, idName string, htmlTag *HtmlTag, matchingDivs *[]*HtmlTag) {
    fmt.Println(htmlTag.Class)
    if htmlTag.XMLName.Local == "div" {
        if htmlTag.Class == className && htmlTag.Id == idName {
            *matchingDivs = append(*matchingDivs, htmlTag)
        }
    }

    for _, tag := range htmlTag.ChildTags {
        getAllCertainDivs(className, idName, &tag, matchingDivs)
    }
}

In the function above, as you can see, I pass a pointer of a slice into the getAllCertainDivs function. At a point a HtmlTag pointer is pushed into the slice matchingDivs. After the append I check the content of the matchingDiv slice, before letting the function call itself recursively again. Then below the if where append was made, the function calls itself recursively one time. And I stop at the fmt.Println(htmlTag.Class) and check the content of matchingDivs slice again. And the content is completely different than before.

There has only been one append, how can the content change ? Does golang use the same HtmlTag pointer, everytime I pass it into next recursive call ?

  • 写回答

1条回答 默认 最新

  • duanjian7343 2016-02-16 18:50
    关注

    The tag variable is declared once at the start of the loop, and the value of tag is overwritten on each iteration. This is the same problem you see in the FAQ with: "What happens with closures running as goroutines?"

    You can declare a new variable during each iteration to get a unique pointer for the function call:

    for _, tag := range htmlTag.ChildTags {
        tag := tag
        getAllCertainDivs(className, idName, &tag, matchingDivs)
    }
    

    Alternatively you can elide the range value, and use the index directly:

    for i := range htmlTag.ChildTags {
        getAllCertainDivs(className, idName, &htmlTag.ChildTags[i], matchingDivs)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?