如何以递归方式更新结构片断?

问题描述 投票:0回答:2

对于下面的代码,我希望得到的输出是 {"NewName" [{"NewName" []}]} 但它没有更新子结构。我们如何确保它更新层次结构中的每个结构。

package main

import (
    "fmt"
)

type red struct {
    Name string
    Child []red
}

func (r *red) setName(nameString string){
    r.Name = nameString
    for _, child := range r.Child{
        child.setName(nameString)
    }
}

func main() {
    obj := red{Name:"NameA",Child:[]red{red{Name: "NameB"}}}
    fmt.Print(obj)
    fmt.Print("\n")

    obj.setName("NewName")
    //Expectation {"NewName" [{"NewName" []}]}
    fmt.Print(obj)
}
go recursion struct slice
2个回答
1
投票

你不需要像其他答案所建议的那样到处使用指针。你的代码中的问题是,当你迭代childs时,你得到了每个copy的值,在这个copy上设置了名字,但没有把这个copy保存到slice中。

package main

import (
    "fmt"
)

type red struct {
    Name  string
    Child []red
}

func (r *red) setName(s string) {
    r.Name = s
    for i, ch := range r.Child {
        ch.setName(s) // ch is not a ptr to r.Child[i], it is a value copy
        r.Child[i] = ch // so you must re assign the copy into the slice!
    }
}

func main() {
    obj := red{Name: "A", Child: []red{red{Name: "B"}}}
    fmt.Print(obj)
    fmt.Print("\n")

    obj.setName("X")
    //Expectation {X [{X []}]}
    fmt.Print(obj)
}

1
投票

其实问题出在这里

for _, ch := range r.Child{
        ch.setName(s)
}

你正在更新使用 ch 这是不更新的你 r.Child 实际上是切片。你的代码相当于这样

var ch red
for i, _:= range r.Child{
    ch = r.Child[i]
    ch.setName(s)
}

为了解决这个问题,你可以这样更新片子。

for i, _ := range r.Child {
    r.Child[i].setName(s) // access the slice eliment by index and update
}

而这是一个很好的模式,可以使用 []*red 为孩子。


0
投票

你应该让 Child[]*red 而不是 []red 以防止红色的副本被创建。

请看下面的调整(the String 方法只是为了让输出看起来更漂亮,否则我们会得到内存地址打印)。)

package main

import (
    "fmt"
)

type red struct {
    Name  string
    Child []*red
}

func (r *red) String() string {
    ret := fmt.Sprintf("{%s [", r.Name)
    for _, c := range r.Child {
        ret = ret + c.Name + " "
    }
    ret += "]}"
    return ret
}

func (r *red) setName(s string) {
    r.Name = s
    for _, ch := range r.Child {
        ch.setName(s)
    }
}

func main() {
    obj := red{Name: "A", Child: []*red{&red{Name: "B"}}}
    fmt.Print(obj)
    fmt.Print("\n")

    obj.setName("X")
    //Expectation {X [{X []}]}
    fmt.Print(obj)
}

0
投票

你可以通过改变 Child []red 到一个指针列表。Child []*red.

下面是完整的代码 去游乐场

package main

import (
    "fmt"
)

type red struct {
    Name string
    Child []*red
}

func (r *red) setName(s string){
    r.Name = s
    for _, ch := range r.Child{
        ch.setName(s)
    }
}

func main() {
    obj := red{Name:"A",Child:[]*red{&red{Name: "B"}}}
    fmt.Println(obj.Name)
    for _, ch := range obj.Child{
       fmt.Println(ch.Name)
    }
    fmt.Print("\n")

    obj.setName("X")
    //Expectation X \n X
    fmt.Println(obj.Name)
    for _, ch := range obj.Child{
       fmt.Println(ch.Name)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.