簡體   English   中英

Go-具有數組和丟失值的遞歸結構

[英]Go - recursive struct with array and losing values

我創建了一個具有父級和子級的Element結構,創建了一個名為SubElement的輔助函數,以及一個遍歷所有子級進行打印的String方法:

package main

import "fmt"

type Element struct {
  parent *Element
  children []Element
  tag string
}

func SubElement(parent *Element, tag string) Element {
  el := Element{}
  el.parent = parent
  el.tag = tag
  parent.children = append(parent.children, el)
  return el
}

func (el Element) String() string {
  s := "<" + el.tag + ">"
  for _, child := range el.children {
    s += child.String()
  }
  s += "</" + el.tag + ">"
  return s
}

func main() {
  root := Element{}
  root.tag = "root"

  a := SubElement(&root, "a")
  b := SubElement(&a, "b")
  SubElement(&b, "c")

  fmt.Println(root) // prints: <root><a></a></root>
  fmt.Println(a) // prints: <a><b></b></a>
  // and so on
}

我遇到的問題是,我選擇打印的根節點中只有第一層子級可用。 我確定它與對parent.children使用append有關,但是缺乏對如何正確解決此問題的理解。

要解決此問題,我將children更改為map[int]Element 然后,在我的SubElement函數中,我將parent.children[len(parent.children)] = el添加到“追加”位置。 然后以正確的順序進行迭代,String方法for循環for i:= 0; i < len(el.children); i++ for i:= 0; i < len(el.children); i++ for i:= 0; i < len(el.children); i++ ,訪問el.children[i]

不過,我想知道如何使用數組正確執行此操作。 謝謝

解釋為什么[] Element版本不起作用的答案。

結構被復制為值。 SubElement ,創建一個Element結構,然后在附加它時,實際上會附加一個新的結構副本。 當您返回EL並將其分配給a ,使另一個副本。 地址a不是地址Element是被追加。

因此,您可能會很棘手,並獲取切片中實際存在的元素的地址,甚至看起來它在測試用例中也可以正常工作,但是保留這些指針(如將其存儲回去時的指針)存在一個問題在Element.parent 問題在於后續的追加可以重新分配切片,現在您保留的指針指向某個孤立的內存,而不是當前有效的切片。

如果[] * Element版本解決了其他一些問題,則可能是存儲了隨后孤立的指針的問題。

可以用結構片實現一棵樹,但是要清楚地理解,將指針保留在片中通常是一個錯誤。 由於存儲父指針並不安全,因此最好僅將其從結構中刪除。

package main

import "fmt"

func main() {
    tree := Element{tag: "head"}
    tree.SubElement("tier-1")
    tree.children[0].SubElement("tier-2")
    tree.children[0].SubElement("tier-2")
    tree.SubElement("tier-1")
    tree.children[1].SubElement("tier-2")
    fmt.Println(tree)
}

type Element struct {
    children []Element
    tag      string
}

func (parent *Element) SubElement(tag string) {
    parent.children = append(parent.children, Element{tag: tag})
}

func (el Element) String() string {
    s := "<" + el.tag + ">"
    for _, child := range el.children {
        s += child.String()
    }
    s += "</" + el.tag + ">"
    return s
}

該代碼至少有效。 但是如果您有其他使用指針的代碼或使用父指針的代碼,則必須重新考慮。

第一個線索是SubElement不會在您原來擁有的地方編譯(編輯:擁有它)。您可以嘗試使其工作,但我建議您將Element.children更改為[]*Element而不是[]Element 這是一個工作示例:

package main

import "fmt"

func main() {
    tree := &Element{tag: "head"}
    t1 := SubElement(tree, "tier-1")
    SubElement(t1, "tier-2")
    SubElement(t1, "tier-2")
    t1 = SubElement(tree, "tier-1")
    SubElement(t1, "tier-2")
    fmt.Println(tree)
}

type Element struct {
    parent   *Element
    children []*Element
    tag      string
}

func SubElement(parent *Element, tag string) *Element {
    el := &Element{parent: parent, tag: tag}
    parent.children = append(parent.children, el)
    return el
}

func (el *Element) String() string {
    s := "<" + el.tag + ">"
    for _, child := range el.children {
        s += child.String()
    }
    s += "</" + el.tag + ">"
    return s
}

輸出:

<head><tier-1><tier-2></tier-2><tier-2></tier-2></tier-1><tier-1><tier-2></tier-2></tier-1></head>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM