2012-04-25 2 views
0

배열과 손실 값 재귀 구조체는 하위 요소라는 도우미 FUNC 및 문자열 방법을 만든 인쇄 모든 어린이를 반복 :이동 - 나는 부모와 자식이있는 요소 구조체를 생성

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를 사용하는 것과 관련이있을 것이라고 확신하지만 올바르게 해결하는 방법에 대한 이해가 부족합니다.

이 문제를 해결하기 위해 childrenmap[int]Element으로 변경했습니다. 그런 다음 내 하위 요소 func에 parent.children[len(parent.children)] = el으로 "추가"합니다. 그런 다음 올바른 순서로 반복하기 위해 for 루프의 String 메소드는 for i:= 0; i < len(el.children); i++이고 el.children[i]에 액세스합니다.

여전히 배열을 사용하여 올바르게 수행하는 방법을 알고 싶습니다. 감사합니다

+0

다른 레벨의 트리를 빌드 할 때 코드를 게시 할 수 있습니까? – Blacksad

+0

완전한 예제와 출력을 가진 샘플을 업데이트했으며, 실제로 출력 결과는 – dskinner

답변

2

첫 번째 실마리는 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> 
+0

입니다.'children [] * Element'과'parent.children = append (parent.children, & el) '를 사용하여 비슷한 결과를 얻었습니다.'SubElement (& parent, "태그")'를'SubElement (parent, "tag")'로 변경하면서'el : = & Element {}'를 사용하고'* Element'를 반환하는 것은 효과가있는 것처럼 보입니다. 그러나 나는 내 다른 접근법에도 무엇이 잘못되었는지를 설명합니다. – dskinner

+0

코드 샘플 – dskinner

4

에서 [] 요소 버전이 작동하지 않은 이유를 설명에 대한 답변.

구조체는 값으로 복사됩니다. SubElement에서 하나의 Element 구조체를 만든 다음 추가 할 때 구조체의 새로운 복사본을 실제로 추가합니다. el을 돌려주고 a에게 할당하면, 그것은 또 하나의 복사본이됩니다. a의 주소는 추가 된 Element의 주소가 아닙니다.

따라서, 실제로는 슬라이스에있는 요소의 주소를 가져 가면 테스트 케이스에서 작동하는 것처럼 보일 수도 있지만, 다음과 같은 경우에는 이러한 포인터 중 하나를 유지하는 데 문제가 있습니다. 너는 Element.parent에 그것을 다시 저장한다. 문제는 후속 추가가 슬라이스를 재 할당 할 수 있고 이제 보존 된 포인터가 현재 유효한 슬라이스가 아닌 분리 된 메모리를 가리키고 있다는 것입니다.

[] * 요소 버전이 다른 문제를 해결하면 이후에 고아가 된 포인터를 저장하는 문제 였을 가능성이 큽니다.

슬라이스 구조체를 사용하여 트리를 구현할 수는 있지만 일반적으로 포인터를 슬라이스에 유지하는 것은 실수입니다. 부모 포인터를 저장하는 것은 안전하지 않으므로 구조체에서 제거하는 것이 가장 좋습니다.

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 
} 

이 코드는 적어도 작동합니다. 하지만 포인터로 작업하는 다른 코드가 있거나 부모 포인터를 사용했다면 다시 생각해야합니다.

+0

(C가 거의없는 배경) 덕분에 다른 문제도 해결되었습니다. Im는 들여 쓰기 기반 템플리트를 처리하며 현재 구문 분석 중이기 때문에 부모를 가리키는 것을 필요로합니다. 변수 들여 쓰기를 포함 할 수있는 두 개의 별도의 둥지 아래에있는 동일한 들여 쓰기 블록에있는 두 줄은 부모를 결정할만큼 충분한 정보를 제공하지 않으므로 처리 중에 특정 들여 쓰기 지점의 마지막 항목에 대한 별도의 참조 트리를 유지합니다. 나는 최종 결과가 문자열이기 때문에 전체 엉망이 수집 된 가비지를 얻을 것이라고 상상하지만 개선을 위해 고려해야 할 사항이 충분히 있습니다. 다시 한 번 감사드립니다. – dskinner