【问题标题】:Append slice of struct into another将结构切片附加到另一个
【发布时间】:2019-04-12 16:09:07
【问题描述】:

我是 Golang 的新手,正在尝试将一个结构切片的内容附加到另一个实例中。数据被附加,但在方法之外是不可见的。下面是代码。

package somepkg

import (
    "fmt"
)

type SomeStruct struct {
    Name  string
    Value float64
}

type SomeStructs struct {
    StructInsts []SomeStruct
}

func (ss SomeStructs) AddAllStructs(otherstructs SomeStructs) {

    if ss.StructInsts == nil {
        ss.StructInsts = make([]SomeStruct, 0)
    }

    for _, structInst := range otherstructs.StructInsts {
        ss.StructInsts = append(ss.StructInsts, structInst)
    }

    fmt.Println("After append in method::: ", ss.StructInsts)
}

然后在主包中初始化结构并调用 AddAllStructs 方法。

package main

import (
  "hello_world/somepkg"
  "fmt"
)

func main() {
    var someStructs = somepkg.SomeStructs{
      []somepkg.SomeStruct{
        {Name: "a", Value: 1.0},
        {Name: "b", Value: 2.0},
      },
    }

    var otherStructs = somepkg.SomeStructs{
      []somepkg.SomeStruct{
        {Name: "c", Value: 3.0},
        {Name: "d", Value: 4.0},
      },
    }

    fmt.Println("original::: ", someStructs)
    fmt.Println("another::: ", otherStructs)

    someStructs.AddAllStructs(otherStructs)

    fmt.Println("After append in main::: ", someStructs)
}

上面的程序输出如下:

original:::  {[{a 1} {b 2}]}
another:::  {[{c 3} {d 4}]}
After append in method:::  [{a 1} {b 2} {c 3} {d 4}]
After append in main:::  {[{a 1} {b 2}]}

我试图了解我在这里缺少什么,因为数据在方法中是可见的。感谢您对此的任何帮助。

-- Anoop

【问题讨论】:

    标签: go struct slice


    【解决方案1】:

    使用指针接收器:

    func (ss *SomeStructs) AddAllStructs(otherstructs SomeStructs) {
    
        if ss.StructInsts == nil {
            ss.StructInsts = make([]SomeStruct, 0)
        }
    
        for _, structInst := range otherstructs.StructInsts {
            ss.StructInsts = append(ss.StructInsts, structInst)
        }
    
        fmt.Println("After append in method::: ", ss.StructInsts)
    }
    

    如果方法需要改变接收者,接收者必须是指针

    【讨论】:

      【解决方案2】:

      你必须返回append的结果:

      package main
      
      import (
          "fmt"
      )
      
      func main() {
          // Wrong
          var x []int
          _ = append(x, 1)
          _ = append(x, 2)
      
          fmt.Println(x) // Prints []
      
          // Write
          var y []int
          y = append(y, 1)
          y = append(y, 2)
      
          fmt.Println(y) // Prints [1 2]
      }
      

      【讨论】:

      • 我在 AddAllStructs 方法中这样做。 append 的结果被分配回StructInsts 并且附加值在方法中被正确打印。
      • 是的,但您不会从AddAllStructs 退回它。因此,当您发送otherStructs 时,您发送的是对一件事的引用(在本例中为nil),但是append 创建了一块新的内存来为新条目腾出空间。当您不返回它时,该引用将在函数范围内丢失。你必须从函数中返回它。
      【解决方案3】:

      你可以通过使用指针接收器而不是值接收器来轻松解决这个问题。

      func (ss *SomeStructs) AddAllStructs(otherstructs SomeStructs) {
      
          if ss.StructInsts == nil {
              ss.StructInsts = make([]SomeStruct, 0)
          }
      
          for _, structInst := range otherstructs.StructInsts {
              ss.StructInsts = append(ss.StructInsts, structInst)
          }
      
          fmt.Println("After append in method::: ", ss.StructInsts)
      } 
      

      记住,如果你看到切片内部,它是一个包含指向数据结构的指针的结构。

      所以main中的slice,不知道新添加的slice的容量,并且已经打印了同一个slice。

      其次,您不必返回附加切片的结果。 这里指针接收器是救命的,因为值接收器不能改变原始值。

      在 go playground 运行代码: https://play.golang.org/p/_vxx7Tp4dfN

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-12-05
        • 2016-12-24
        • 1970-01-01
        • 2019-07-14
        • 1970-01-01
        • 2021-06-04
        • 2020-07-06
        相关资源
        最近更新 更多