【问题标题】:How to update slice of struct in recursive fashion如何以递归方式更新结构切片
【发布时间】:2020-09-21 15:40:58
【问题描述】:

对于下面的代码,我期待{"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


    【解决方案1】:

    您无需按照其他答案的建议到处使用指针。

    您的代码中的问题是,当您迭代子项时,您会通过副本为每个项目获取一个值,然后在副本上设置名称。

    但是由于您没有将修改后的值复制回切片中,因此不会保留更改。

    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)
    }
    

    【讨论】:

      【解决方案2】:

      其实问题就在这里

      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 是一个很好的模式。

      【讨论】:

        【解决方案3】:

        您可以通过将Child []red 更改为指针列表来做到这一点:Child []*red

        这是Go playground中的完整代码

        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)
            }
        }
        

        【讨论】:

          【解决方案4】:

          您应该将Child 设为[]*red 而不是[]red,以防止创建红色副本。

          请参阅以下调整(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)
          }
          

          【讨论】:

            猜你喜欢
            • 2019-01-28
            • 1970-01-01
            • 2014-09-20
            • 1970-01-01
            • 2020-02-03
            • 2019-09-15
            • 2023-03-18
            • 2014-08-24
            • 2023-03-17
            相关资源
            最近更新 更多